## bash script
foo(){
sleep 0.0001
read -s -t 0.0002 var ## get the pipeline input if have
if [ -n "$var" ];then
echo "has pipe input"
fi
if [ $# -gt 0 ];then
echo "has std input"
fi
read -s -t 30 var1 #1 # expect wait for 30 seconds , but acturaly not
echo "failed"
read -s -t 30 var2 #2
echo "failed again"
}
echo "ok1"| foo "ok"
## output:
has pipe input
has std input
failed
failed again
如果foo有管道输入,则#1和#2处的读取命令将立即返回,而无需等待输入TIMEOUT
在我的真实脚本中,有三个需求:
1个使函数可以同时接受管道输入和参数(因为我希望我的函数可以从管道输入中进行配置,所以我认为这对我很好。例如:)
foo(){
local config
sleep 0.0001
read -t 0.0002 config
eval "$config"
}
then i can pass configuration like this
foo para1 para2 <<EOF
G_TIMEOUT=300
G_ROW_SPACE=2
G_LINE_NUM=10
EOF
2在我的功能中,我需要从键盘读取用户输入(我需要使用 read 与用户进行交互)
3等待用户输入应该有一个超时(我想添加一个屏幕保护程序,如果在用户经过TIMEOUT秒后没有任何动作,将调用屏幕保护程序脚本,并且在按下任何键后,屏幕保护程序将返回,并再次等待使用输入
如果有一种方法可以在我获得管道输入后将管道输入重定向到fd3,然后关闭fd3以使管道断开,然后将fd0重新打开到标准输入(键盘)并等待用户输入?
答案 0 :(得分:1)
它不等待输入,因为它已经到达管道的末端。
echo "ok1" | ...
将单个行写入管道,然后将其关闭。函数中的第一个read
将ok1
读入var
。所有其他read
调用将立即返回,因为没有更多的数据可读取,并且以后由于管道的写端已被关闭而没有更多的数据出现。
如果您希望管道保持打开状态,则必须执行类似的操作
{ echo ok1; sleep 40; echo ok2; } | foo
答案 1 :(得分:0)
作为answer of melpomene的附加内容,您可以在执行以下行时看到:
$ echo foo | { read -t 10 var1; echo $?; read -t 10 var2; echo $?; }
0
1
$ read -t 1 var; echo $?
142
此行输出read
的返回码和手动状态
返回码为零,除非遇到文件结尾,读取超时(在这种情况下,返回码大于128)或无效 文件描述符作为-u
的参数提供来源:
man bash
由此可见,由于达到了EOF,因此第一个命令中的第二次读取失败。
答案 2 :(得分:0)
因为函数foo具有管道输入,所以在子进程中,输入fd自动重定向到管道,只需将标准输入重定向到键盘(/ proc / pid / 0),即可获得管道输入,将解决问题< / p>
感谢那些家伙给我的提示,这不是读命令问题,而是fd问题。
foo(){
local config
sleep 0.0001
read -t 0.0002 config
if [ -n "$config" ];then
config=$(cat -)
fi
echo "$config"
exec 3</dev/tty
read -t 10 -u 3 input
echo "success!"
}
更好的方法:
foo(){
local config
sleep 0.0001
read -t 0.0002 config
if [ -n "$config" ];then
config=$(cat -)
fi
exec 0<&- ## close current pipeline input
exec 0</dev/tty ##reopen input fd with standard input
read -t 10 input ##read will wait for input for keyboard :) good !
echo "success!"
}
此外,如果我可以检测到当前输入是管道输入还是标准输入,我不会使用read config来判断是否有管道输入,但是如何实现呢? [-t 0]是个好主意
更好的方法:
foo(){
local config
if [ ! -t 0 ];then
config=$(cat -)
exec 0<&- ## close current pipeline input
exec 0</dev/tty ##reopen input fd with standard input
fi
read -t 10 input ##read will wait for input for keyboard :) great !
echo "success!"
}