bash:在也使用read的循环中嵌套的交互式读取

bash: nested interactive read within a loop that's also using read

如何在此while循环中编写交互式响应的代码?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/bin/bash

shows=$(< ${HOME}/.get_iplayer/tv.cache)

# ...
# ... stuff with shows omitted ...
# ...

function print_show {
# ...
    return
}

while read -r line
do
    print_show"$line"

    read -n 1 -p"do stuff? [y/n] :" resp  # PROBLEM

# ...
# resp actions omitted
# ...

done <<<"$shows"

因此,读取"已处理"文件,然后将生成的面向行的数据用于while read循环中。

但是while循环中的读取行不能按预期工作,也就是说它不等待用户响应,这可能是因为它被封装在while read上下文中。

你能建议如何解决这个问题还是另一种机制?


你已经正确地确定了原因是

1
while ...; do ...; done <<<"$shows"

循环,stdin被重定向,因此read不再从键盘读取。

您可以使用0以外的文件描述符来解决这个问题;例如,

1
while read -r -u 3 line; do ...; done 3<${HOME}/.get_iplayer/tv.cache

将对文件使用fd 3而不是fd 0,允许正常的read(不使用-u)使用原始stdin,或

1
while ...; do read -n 1 -p"do stuff? [y/n] :" -u 3 resp; done 3<&0 <<<"$shows"

将原来的fd 0克隆到fd 3,然后用字符串替换fd0。


由于您已经将整个文件读取到内存中,请将其读取到数组中而不是单个字符串中。

1
2
3
4
5
6
7
# Requires bash 4 or later
mapfile -t loop_input < $HOME/.get_iplayer/tv.cache

for line in"${loop_input[@]}"; do
    print_show"$line"
    read -n 1 -p"do stuff? [y/n] :" resp
done

如果您仍然使用bash的早期版本,我仍然建议您阅读该文件数组而不是单个字符串,但不太方便。

1
2
3
4
5
6
declare -a loop_input
while read; do loop_input+=("$REPLY"); done

for line in"${loop_input[@]}"; do
    ...
done

或者,您不能将文件全部读取到内存中:

1
2
3
while read -u 3 line; do
    ....
done 3< $HOME/.get_iplayer/tv.cache