我正在尝试确定是否将stdin重定向到文件:
[ ...some condition here... ] && input=$fileName || input="&0"
./myScript < $input
但是那不起作用,因为当变量$ input为“&0”时,bash将其解释为文件名。
但是,我可以做:
if [ ...condition... ];then
./myScript <$fileName
else
./myScript
问题在于,。/ myScript实际上是一个长长的命令行,我不想重复,也不想为其创建函数,因为它也不那么长(不值得)。
然后我想到要这样做:
[ ...condition... ] && input=$fileName || input= #empty
cat $input | ./myScript
但是,这需要再运行一个命令和一个管道(即子外壳)。还有另一种更简单,更有效的方法吗?
首先stdin是文件描述符0(零)而不是1(stdout)。
您可以像这样有条件地复制文件描述符或使用文件名:
[[ some_condition ]] && exec 3<"$filename" || exec 3<&0
some_long_command_line <&3
请注意,如果条件为假,则显示的命令将执行第二个exec
或第一个exec
失败。如果您不想这样做,那么应该使用if
/ else
:
if [[ some_condition ]]
then
exec 3<"$filename"
else
exec 3<&0
fi
但是如果第一次重定向失败(在条件为真之后),那么从文件描述符3进行的后续重定向将失败。
(
if [ ...some condition here... ]; then
exec <$fileName
fi
exec ./myscript
)
在子shell中,有条件地重定向stdin并执行脚本。
标准输入也可以由特殊设备文件/dev/stdin
表示,因此可以将其用作文件名。
file="/dev/stdin"
./myscript < "$file"
怎么样
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)
)可能非常有用,并且组合得很好。
如果小心,可以使用'eval
'和第一个想法。
[ ...some condition here... ] && input=$fileName || input="&1"
eval ./myScript < $input
但是,您说的“ myScript”实际上是一个复杂的命令调用;如果它包含可能包含空格的参数,那么在决定使用'eval
'之前,您必须非常小心。
坦率地说,担心“ cat
”命令的成本可能不值得。这不太可能成为瓶颈。
[更好的是设计myScript
,使其像常规的Unix过滤器一样工作-除非从标准输入中读取一个或多个文件即可工作(例如,以cat
或grep
为例), 。该设计基于长期和完善的经验-因此值得进行仿真,以避免不得不处理此类问题。
使用eval
:
eval
此简单的#! /bin/bash
[ $# -gt 0 ] && input="'"$1"'" || input="&1"
eval "./myScript <$input"
替代品
myScript
产生以下输出:
$ ./myDemux myScriptplrep / nib / rsu /!#esrever = _ $$ ./myDemux富钱币酒吧拉布巴兹扎布
注意,它也处理输入中的空格:
$ ./myDemux foo \ bareman eht ni ecaps a htiw elif
要通过管道将输入降低到#! /usr/bin/perl -lp
$_ = reverse
,请使用myScript
:
$ ./myDemux请注意,如果您尝试直接通过管道传递输出,如中所示
$ md5sum / etc / issue | ./myDemux它将挂起,等待来自终端的输入,而process substitution没有此缺点。
稍有变化就会产生所需的行为:
ephemient's answer
人们向您展示很长的脚本,但是....您会遇到bash陷阱:)您必须用bash引用所有内容。例如,您想要名为&0的列表文件。
filename ='&0'#rightls $ filename#错误!这个替代$ filename并解释&0ls“ $ filename” #right
另一个,带空格的文件。
filename ='一些带有空格的文件'ls $ filename#错误,bash剪切了第一个和最后一个空格,并在with和空格词之间减少了多个空格ls“ $ filename” righ
脚本中也是如此。请更改:
#! /bin/bash
[ $# -gt 0 ] && input="'"$1"'" || input=/dev/stdin
eval "./myScript <$input"
to
./myScript < $input
全部。 bash有更多陷阱。我建议出于同样的原因对“ $ file”进行报价。空格和其他无法解释的字符总是会引起问题。
但是/ dev / stdin呢?仅当您重定向标准输入并想将某些内容打印到实际标准输入时,此功能才可用。
因此,您的脚本应显示如下:
./myScript < "$input"