如何从stdin读取数据并读取用户对每行数据的响应

时间:2012-08-13 00:16:22

标签: bash stdin interaction

使用bash我想读取行列表并询问用户脚本是否应该在读取时处理每一行。由于行和用户的响应来自stdin,如何协调文件句柄?经过多次搜索和试用后错误我提出了示例

exec 4<&0
seq 1 10 | while read number
do
    read -u 4 -p "$number?" confirmation
    echo "$number $confirmation"
done

这里我们使用exec在文件句柄4上重新打开stdin,从管道stdin中读取数字序列,并在文件句柄4上获取用户的响应。这看起来太多了。这是解决这个问题的正确方法吗?如果没有,有什么更好的方法?感谢。

3 个答案:

答案 0 :(得分:3)

您可以强制read从终端获取其输入,而不是更抽象的标准输入:

while read number
do
    < /dev/tty read -p "$number?" confirmation
    echo "$number $confirmation"
done

缺点是您无法自动接受(例如,通过读取连接到yes的管道)。

答案 1 :(得分:1)

是的,使用额外的文件描述符是解决此问题的正确方法。管道只能将一个命令的标准输出(文件描述符1)连接到另一个命令的标准输入(文件描述符1)。因此,当您解析命令的输出时,如果您需要从其他来源获取输入,则必须通过文件名或文件描述符来提供其他源。

我会以不同的方式编写这个,使重定向本地化为循环,但这不是什么大问题:

seq 1 10 | while read number
do
    read -u 4 -p "$number?" confirmation
    echo "$number $confirmation"
done 4<&0

使用bash以外的shell,如果-u没有read选项,则可以使用重定向:

printf "%s? " "$number"; read confirmation <&4

您可能对other examples of using file descriptor reassignment感兴趣。

另一种方法,如pointed out by chepner,是从一个命名文件中读取,即/dev/tty,它是程序运行的终端。这使得脚本更简单但缺点是您无法轻松手动将确认数据提供给脚本。

答案 2 :(得分:0)

对于您的申请killmatching,两次通行证是完全正确的方法。

  • 在第一遍中,您可以将所有匹配的进程读入数组。这个数字很小(通常几十个,最多几万个),所以没有效率问题。代码看起来像

    set -A candidates
    ps | grep | while read thing do candidates+=("$thing"); done
    

    (句法细节可能有误;我的bash生锈了。)

  • 第二遍将遍历candidates数组并进行互动。

此外,如果您的平台上有该版本,则可能需要查看pgrep。它并不理想,但它可以为您节省一些分支,这比世界上所有的阵列查找都要贵。