我试图这样做以决定是否将stdin重定向到文件:
[ ...some condition here... ] && input=$fileName || input="&0"
./myScript < $input
但这不起作用,因为当变量$ input为“&amp; 0”时,bash会将其解释为文件名。
但是,我可以这样做:
if [ ...condition... ];then
./myScript <$fileName
else
./myScript
问题是./myScript实际上是一个我不想复制的长命令行,也不想为它创建一个函数,因为它也不长(它不值得)。
然后我突然想到这样做:
[ ...condition... ] && input=$fileName || input= #empty
cat $input | ./myScript
但是这需要再运行一个命令和一个管道(即子壳) 还有另一种方法更简单,更有效吗?
答案 0 :(得分:24)
首先,stdin是文件描述符0(零)而不是1(stdout)。
您可以像这样有条件地复制文件描述符或使用文件名:
[[ some_condition ]] && exec 3<"$filename" || exec 3<&0
some_long_command_line <&3
请注意,如果条件为false 或第一个exec
失败,则显示的命令将执行第二个exec
。如果您不希望有可能失败,那么您应该使用if
/ else
:
if [[ some_condition ]]
then
exec 3<"$filename"
else
exec 3<&0
fi
但是如果第一次重定向失败(在条件为真之后),则文件描述符3的后续重定向将失败。
答案 1 :(得分:7)
(
if [ ...some condition here... ]; then
exec <$fileName
fi
exec ./myscript
)
在子shell中,有条件地重定向stdin并执行脚本。
答案 2 :(得分:5)
标准输入也可以由特殊设备文件/dev/stdin
表示,因此将其用作文件名将起作用。
file="/dev/stdin"
./myscript < "$file"
答案 3 :(得分:2)
怎么样
function runfrom {
local input="$1"
shift
case "$input" in
-) "$@" ;;
*) "$@" < "$input" ;;
esac
}
我使用减号表示标准输入,因为这对于许多Unix程序来说都是传统的。
现在你写了
[ ... condition ... ] && input="$fileName" || input="-"
runfrom "$input" my-complicated-command with many arguments
我发现这些将命令作为参数(例如xargs(1)
)的函数/命令非常有用,并且它们组合得很好。
答案 4 :(得分:2)
如果您小心,可以使用“eval
”和您的第一个想法。
[ ...some condition here... ] && input=$fileName || input="&1"
eval ./myScript < $input
但是,你说'myScript'实际上是一个复杂的命令调用;如果涉及可能包含空格的参数,那么在决定使用“eval
”之前必须非常小心。
cat
”命令的成本可能不值得这么麻烦;它不太可能成为瓶颈。
更好的是设计myScript
以便它像普通的Unix过滤器一样工作 - 它从标准输入读取,除非给它一个或多个文件起作用(例如,cat
或{ {1}}例如)。这种设计基于长期和完善的体验 - 因此值得模仿,以避免不得不处理这样的问题。
答案 5 :(得分:1)
使用eval
:
#! /bin/bash
[ $# -gt 0 ] && input="'"$1"'" || input="&1"
eval "./myScript <$input"
myScript
#! /usr/bin/perl -lp
$_ = reverse
产生以下输出:
$ ./myDemux myScript pl- lrep/nib/rsu/ !# esrever = _$ $ ./myDemux foo oof bar rab baz zab
请注意,它也处理输入中的空格:
$ ./myDemux foo\ bar eman eht ni ecaps a htiw elif
要将输入传输到myScript
,请使用process substitution:
$ ./myDemux <(md5sum /etc/issue) eussi/cte/ 01672098e5a1807213d5ba16e00a7ad0
请注意,如果您尝试直接管道输出,如
$ md5sum /etc/issue | ./myDemux
它将等待来自终端的输入,而ephemient's answer没有这个缺点。
稍微改变会产生所需的行为:
#! /bin/bash
[ $# -gt 0 ] && input="'"$1"'" || input=/dev/stdin
eval "./myScript <$input"
答案 6 :(得分:0)
人们向你展示很长的剧本,但是......你得到了bash陷阱:) 你必须用bash引用一切。 例如,您需要名为&amp; 0的列表文件。
filename ='&amp; 0'#right ls $ filename #wrong!这个替换$ filename并解释&amp; 0 ls“$ filename”#right
另一个是带空格的文件。
filename ='带空格的文件' ls $ filename #wrong,bash剪切第一个和最后一个空格,并减少with和空格之间的多个空格 ls“$ filename”righ
在您的脚本中也是如此。请改变:
./myScript < $input
到
./myScript < "$input"
一切。 bash有更多的陷阱。 我建议出于同样的原因为“$ file”报价。除了可以解释的空格和其他字符总是会产生问题。
但/ dev / stdin怎么样?只有当您重定向stdin并想要将内容打印到真正的标准输入时,这才可用。
所以,你的脚本应该这样显示:
[ ...some condition here... ] && input="$fileName" || input="&0"
./myScript < "$input"