【问题标题】:Reading keys fails inside a while read loop在 while 读取循环内读取密钥失败
【发布时间】:2014-12-08 11:06:17
【问题描述】:

这是我检测按键按下的脚本:

#!/bin/bash
echo "Reading keys."
while [ "x$keypress" = "x" ]; do
  read -n 1 -t 1 -s keypress
  printf "."
done
printf "\n"
echo "Pressed key: "$keypress

这似乎工作正常(例如在一段时间后按“q”键):

$ ./InputKey.sh
Reading keys.
.............................................
Pressed key: q

但是,如果我将它放在一个循环中,该循环会读取我的File.txt 并等待每一行的键:

#!/bin/bash
MyList=File.txt
while IFS=, read -ra ListLine
do
    echo "Processing line: "$ListLine
    echo "Press [S] to count as Secret or [P] to count as Public."
  while [ "x$keypress" = "x" ]; do
        read -n 1 -t 1 -s keypress
    printf "."
    done
    printf "\n"
    echo "Pressed key: "$keypress
done < "$MyList"

程序根本不等待按键,这是奇怪的结果:

$ ./prueba07.sh
Processing line: d:\Temp
Press [S] to count as Secret or [P] to count as Public.
.
Pressed key: c
Processing line: :\Temp
Press [S] to count as Secret or [P] to count as Public.

Pressed key: c
Processing line: e:\Temp
Press [S] to count as Secret or [P] to count as Public.

Pressed key: c
Processing line:
Press [S] to count as Secret or [P] to count as Public.

Pressed key: c

这是File.txt的内容:

d:\Temp
c:\Temp
e:\Temp 

我在某处读到问题来自 &lt;"$MyList" 重定向器,它消耗了所有 stdin

所以,我找到了this thread 并添加了&amp;3 重定向器:

#!/bin/bash
MyList=File.txt
while IFS=, read -ra ListLine <&3
do
    echo "Processing line: "$ListLine
    echo "Press [S] to count as Secret or [P] to count as Public."
  while [ "x$keypress" = "x" ]; do
        read -n 1 -t 1 -s keypress
    printf "."
    done
    printf "\n"
    echo "Pressed key: "$keypress
done 3< "$MyList"

现在程序等待一键按下。但其余部分会自动重复(例如仅按一次 p 时):

$ ./prueba07.sh
Processing line: d:\Temp
Press [S] to count as Secret or [P] to count as Public.
..
Pressed key: p
Processing line: c:\Temp
Press [S] to count as Secret or [P] to count as Public.

Pressed key: p
Processing line: e:\Temp
Press [S] to count as Secret or [P] to count as Public.

Pressed key: p
Processing line:
Press [S] to count as Secret or [P] to count as Public.

Pressed key: p

这样的问题怎么解决? 谢谢你。

EDIT-01:针对读取关键行测试了此更改,但没有结果:

read -n 1 -t 1 -s keypress </dev/tty

this other 线程中提取。

EDIT-02:在 Ubuntu Desktop v12 和 CygWin (Windows 7) 上测试。

EDIT-03:下面的答案是正确的。我为脚本选择的最后一个更改是(最后只有一行):

#!/bin/bash
MyList=File.txt
while IFS=, read -ra ListLine <&3
do
    echo "Processing line: "$ListLine
    echo "Press [S] to count as Secret or [P] to count as Public."
  while [ "x$keypress" = "x" ]; do
        read -n 1 -t 1 -s keypress
    printf "."
    done
    printf "\n"
    echo "Pressed key: "$keypress
    unset keypress
done 3< "$MyList"

【问题讨论】:

    标签: shell stdin io-redirection


    【解决方案1】:

    您可以从不同的文件描述符中读取,并重构内部循环

    while IFS=, read -r -u 3 -a ListLine
    do
      echo 'Processing line:' "$ListLine"
      echo 'Press [S] to count as Secret or [P] to count as Public.'
      until read -n 1 -t 1 -s keypress
      do
        printf .
      done
      echo
      echo 'Pressed key:' $keypress
    done 3< File.txt
    

    Does bash support doing a read nested within a read loop?

    【讨论】:

    • 您的脚本似乎有细微的修改,但我认为它是正确的。让我们注意到while IFS=, read -r -u 3 -a ListLinewhile IFS=, read -ra ListLine &lt;&amp;3 是等价的。
    【解决方案2】:

    它在第一个循环之后工作,因为 keypress 是空的,但在随后的调用中,keypress 仍然设置为第一次通过循环时设置的值。 您只需要将 keypress 变量设置为空字符串。

    【讨论】:

    • 嗯.. 我正在测试它,看来你是对的,克劳迪奥。谢谢。您应该编辑您的答案以增强它以适应论坛规则。至少,我认为您必须添加一个示例(只需一个简单的脚本模型就足够了)。谢谢你。
    猜你喜欢
    • 2023-04-05
    • 2013-07-08
    • 1970-01-01
    • 1970-01-01
    • 2017-12-09
    • 2011-03-05
    • 2015-01-04
    • 1970-01-01
    • 2020-03-26
    相关资源
    最近更新 更多