3

使用 bash 我想读取行列表并询问用户脚本是否应在读取每一行时对其进行处理。由于行和用户的响应都来自标准输入,如何协调文件句柄?经过大量搜索和反复试验,我想出了这个例子

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

在这里,我们使用 exec 重新打开文件句柄 4 上的标准输入,从管道标准输入中读取数字序列,并获取用户对文件句柄 4 的响应。这似乎工作量太大。这是解决这个问题的正确方法吗?如果没有,有什么更好的方法?谢谢。

4

3 回答 3

2

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

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

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

于 2012-08-13T13:17:44.640 回答
1

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

我会写这个有点不同,使重定向本地到循环,但这没什么大不了的:

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

对于 bash 以外的 shell,在没有-uto 选项的情况下read,您可以使用重定向:

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

您可能对使用文件描述符重新分配的其他示例感兴趣。

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

于 2012-08-16T19:01:20.973 回答
0

对于您的应用程序,killmatching,两次通过是完全正确的方法。

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

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

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

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

此外,如果它在您的平台上可用,您可能需要查看pgrep. 这并不理想,但它可能会为您节省一些分叉,这比世界上所有的数组查找成本都要高。

于 2012-08-13T01:11:18.757 回答