假设我有一个名为confirmation.sh
以下内容的文件:
#!/bin/bash
echo -n "Are you sure [Y/n]? "
read line
case "$line" in
n|N) echo "smth"
;;
y|Y) echo "smth"
;;
esac
我想按以下方式运行该脚本:
cat confirmation.sh | sh
我明白了Are you sure [Y/n]?
,剧本被打断了。有什么问题?
答案1
正如其他人所说,这是因为stdin
ofsh
已被重定向以从管道读取,它没有像通常那样连接到终端。为了解决这个问题,您可以做的一件事是使用/dev/tty
强制脚本从终端读取。例如:
#!/bin/sh
read -p "Are you sure [Y/n]?" line </dev/tty
case "$line" in
y|Y) echo "confirmed"
;;
*) echo "not confirmed"
;;
esac
通常,只有当您特别想要阻止人们编写输入脚本时,您才会执行此操作,例如:
echo Y | sh confirmation.sh
即使用户可能希望Y
在提示时自动输入,它仍然会从终端读取。对于需要密码来执行此操作的程序来说,这是很常见的。
答案2
sh 3<<CONFIRM /dev/fd/3
$(cat ./confirmation.sh)
CONFIRM
sh 3<./confirmation.sh /dev/fd/3
笔记:感谢@Graeme 纠正我上面两个例子......
如果你坚持的话,会容易得多stdin
清除。
2<./confirmation.sh . /dev/stderr
或者,由于终端的 0 1 2 都是同一个文件,只需添加:
read line <&2
和你的
cat ./confirmation.sh | sh
效果很好。
答案3
这对于通过管道传输到我的脚本的单个参数有效:
if [ -p /dev/stdin ]; then set -- "$( cat )"; fi
然后,我可以访问位置参数 ( $1
) 中的管道数据,这与我的其他脚本工作兼容。
从info test
:
[ -p /dev/stdin ]
:-p FILE
如果 FILE 存在并且是命名管道,则为 True。
答案4
简短的回答是你不能。管道将 stdout 重定向到 stdin,因此您无法运行交互式脚本,因为您已经将第一个命令的输出重定向为管道语句中第二个命令的输入。
您可能想做这样的事情:
cat confirmation.sh > ask.sh && sh ask.sh