在bash中是否有习惯模拟Perl钻石操作符的方法?有钻石操作员,
script.sh | ...
读取stdin的输入和
script.sh file1 file2 | ...
读取file1和file2的输入。
另一个约束是我想在script.sh中使用stdin来输入我自己的脚本以外的其他东西。下面的代码执行我想要的file1 file2 ... case,但不适用于stdin上提供的数据。
command - $@ <<EOF
some_code_for_first_argument_of_command_here
EOF
我更喜欢Bash解决方案,但任何Unix shell都可以。
编辑:为了澄清,这是script.sh的内容:
#!/bin/bash
command - $@ <<EOF
some_code_for_first_argument_of_command_here
EOF
我希望这个工作方式与钻石运算符在Perl中的工作方式相同,但它现在只处理文件名作为参数。
编辑2:我不能做任何事情
cat XXX | command
因为命令的stdin不是用户的数据。命令的stdin是here-doc中的数据。我希望用户数据进入我脚本的stdin,但它不能是我脚本中命令调用的标准输入。
答案 0 :(得分:6)
当然,这完全可行:
#!/bin/bash
cat $@ | some_command_goes_here
然后,用户可以不带参数(或“ - ”)调用脚本来读取stdin或多个文件,所有文件都将被读取。
如果你想处理这些文件的内容(比如逐行),你可以这样做:
for line in $(cat $@); do
echo "I read: $line"
done
修改:将$*
更改为$@
以处理文件名中的空格,这要归功于有用的评论。
答案 1 :(得分:4)
有点cheezy,但是怎么样
cat file1 file2 | script.sh
答案 2 :(得分:2)
我(就像其他人一样,似乎)对目标究竟是什么感到有些困惑,所以我会给出三个可能的答案,可能涵盖你真正想要的东西。首先,相对简单的目标是让脚本从文件列表(在命令行中提供)或从常规stdin中读取:
if [ $# -gt 0 ]; then
exec < <(cat "$@")
fi
# From this point on, the script's stdin is redirected from the files
# (if any) supplied on the command line
注意:使用$ @的双引号是避免文件名中有趣字符(例如空格)出现问题的最佳方法 - $ *和未加引号的$ @都会弄乱这个问题。我在这里使用的&lt;()技巧是一个仅限bash的功能;它在后台触发cat以从命令行提供的文件中提供数据,然后我们使用exec将脚本的stdin替换为cat的输出。
......但这似乎并不是你真正想要的。您真正想要的是将提供的文件名或脚本的stdin 作为参数传递给脚本内的命令。这需要相反的过程:将脚本的stdin转换为文件(实际上是命名管道),其名称可以传递给命令。像这样:
if [[ $# -gt 0 ]]; then
command "$@" <<EOF
here-doc goes here
EOF
else
command <(cat) <<EOF
here-doc goes here
EOF
fi
这使用&lt;()通过cat将脚本的stdin清洗到命名管道,然后将其作为参数传递给命令。同时,命令的stdin取自here-doc。
现在,我认为这就是你想要做的,但它并不是你所要求的,而是两者从提供的文件中重定向脚本的stdin 和将stdin传递给脚本中的命令。这可以通过结合上述技术来完成:
if [ $# -gt 0 ]; then
exec < <(cat "$@")
fi
command <(cat) <<EOF
here-doc goes here
EOF
......虽然我不明白为什么你真的想这样做。
答案 3 :(得分:1)
Perl菱形运算符实际上遍历所有命令行参数,将每个参数视为文件名。它打开每个文件并逐行读取。这里有一些bash代码大致相同。
for f in "$@"
do
# Do something with $f, such as...
cat $f | command1 | command2
-or-
command1 < $f
-or-
# Read $f line-by-line
cat $f | while read line_from_f
do
# Do stuff with $line_from_f
done
done
答案 4 :(得分:1)
你想拿第一个参数并用它做一些事情,然后从任何指定的文件中读取,或者如果没有文件则读取stdin?
就个人而言,我建议使用getopt来指示使用“-a value”语法的参数来帮助消除歧义,但那只是我。这是我在bash 中没有 getopts的方式:
firstarg=${1?:usage: $0 arg [file1 .. fileN]}
shift
typeset -a files
if [[ ${#@} -gt 0 ]]
then
files=( "$@" )
else
files=( "/dev/stdin" )
fi
for file in "${files[@]}"
do
whatever_you_want < "$file"
done
如果没有指定args,则?:运算符将会死亡,因为您似乎至少想要一个arg。抓住它之后,将args移动一个,然后使用剩余的args作为文件列表,或者如果没有其他args则使用bash特殊文件句柄“/ dev / stdin”。
我认为“如果没有指定文件,请使用/ dev / stdin - 否则使用命令行上的文件”这段可能就是你要找的,但其余的代码至少对于上下文。
答案 5 :(得分:0)
也有点羞涩,但是怎么样:
if [[ $# -eq 0 ]]
then
# read from stdin
else
# read from $* (args)
fi
如果您需要逐行阅读和处理(可能)并且不想复制/粘贴相同的代码两次(很可能),请在脚本中定义一个函数并传递这些行逐个执行此函数,并在所述函数中处理它们。
答案 6 :(得分:0)
为什么不在脚本中使用``cat @ * ?例如:
x=`cat $*`
echo $x