在读取循环中获取交互式输入的问题

jam*_*gni 5 shell pipe io-redirection input read

我正在做类似于以下最小示例的操作:

#! /bin/sh

# $1 = file containing list of files to sync
# $2 = source dir ; $3 = target dir

cat "$1" | while read f
do
    cp -i "$2"/"$f" "$3"/"$f"
done
Run Code Online (Sandbox Code Playgroud)

我发现它cp -i根本不等待我的输入,循环只会运行到最后。为什么,以及可以做些什么来解决这种情况?

jam*_*gni 6

在这里挖掘,我从https://unix.stackexchange.com/a/56877/54067(其中问题和答案的措辞不同,问题与交互式输入无关)了解到问题的原因是在cp -i希望用户通过给交互式输入确认stdin,但在cat | while read循环stdin是忙于管等将下面的行(多个)从输入文件/咀嚼起来作为用户输入。

因此,该解决方案也类似于另一个问题中建议的解决方案 - 通过与以下不同的文件描述符来管道内容stdin

while read f <&3
do
    cp -i "$2"/"$f" "$3"/"$f"
done 3< "$1"
Run Code Online (Sandbox Code Playgroud)

请注意 <&3,并3< "$1"在循环的顶部和底部。

感谢@StéphaneChazelas 在其他问题中的回答。(我投了赞成票。)

此外,在这里发布这个显然我想知道除此之外是否还有其他交互式输入解决方案。

还要注意,虽然for在另一个 q 中使用循环是可能的,但我担心如果文件很大,$(cat "$1")infor f in "$(cat "$1")"会通过扩展文件来消耗不必要的内存。OTOH 管道应逐行处理读取 IIUC。所以我不认为使用for是一个有效的解决方案。我也想对此发表评论。

  • 您还可以使用 `cp ... &lt; /dev/tty` 将 `cp` 的 stdin 用作控制终端,如果有任何原始(外部)stdin 当前引用的内容。 (3认同)
  • @StéphaneChazelas 然后你的脚本用户会加倍诅咒你,一次是因为使用了 `cp -i`,另一个是让他使用了 `expect` 而不是 `yes |`。 (2认同)