Jes*_*pin 3 bash stdin command-line-parsing
我想编写一个bash脚本,可以处理类似于许多内置bash命令的参数和输入.例如,像sort一样,它可以处理
sort -k 1 -r input.txt
sort input.txt -k 1 -r
cat input.txt | sort -k 1 -r
sort -k 1 -r < input.txt
sort -k 1 -r <(cat input.txt)
Run Code Online (Sandbox Code Playgroud)
我希望我的脚本能够以类似的方式处理参数和输入
myscript.sh -i 3 -b 4 input.txt
myscript.sh input.txt -i 3 -b 4
cat input.txt | myscript.sh -i 3 -b 4
myscript.sh -i 3 -b 4 < input.txt
myscript.sh -i 3 -b 4 <(cat input.txt)
Run Code Online (Sandbox Code Playgroud)
到目前为止,我只使用了"read"和"getopts"中的一些功能,并认为如果我自己尝试这样做可能会出错.
为了让我更清楚地说明我的问题,请输入input.text的内容
aaa
bbb
ccc
Run Code Online (Sandbox Code Playgroud)
我想使用参数i和b中的值来做一些事情,但我只是在这个例子中打印出来.我想要的样本输出是
i : 3
b : 4
aaa
bbb
ccc
Run Code Online (Sandbox Code Playgroud)
编写代码来处理上面的示例命令以提供此输出的最佳方法是什么?
下面是从@chepner的三明治概念中得到的代码,这是迄今为止最好的代码.
#!/bin/bash -l
die () {
echo >&2 "[exception] $@"
exit 1
}
#parse param
while getopts "i:b:" OPTION; do
case "$OPTION" in
i)
i="$OPTARG"
;;
b)
b="$OPTARG"
;;
*)
die "unrecognized option"
;;
esac
done
if [ -e tmpfile ]
then
rm tmpfile
fi
shift $(($OPTIND - 1))
echo "i : "$i
echo "b : "$b
cat $1 > tmpfile
if read -t 0; then
cat >> tmpfile
fi
cat tmpfile
Run Code Online (Sandbox Code Playgroud)
执行摘要:您可以使用它read -t 0来测试标准输入上是否有任何可用输入.它将以状态0退出,数据立即可用于标准输入(通过管道或重定向文件),如果没有则立即可用(例如,仍然连接到键盘).然后,您可以根据是否需要从标准输入读取来分支脚本.
if read -t 0; then
# Do one thing
else
# Do something else
fi
Run Code Online (Sandbox Code Playgroud)
对我来说棘手的部分是编写脚本,这样如果你不管道任何东西,它就不会阻止读取标准输入.
这似乎有效; 改进欢迎.首先,消耗标准输入的所有内容; 然后处理作为参数给出的文件.
# The first call to read only succeeds when there is input
# available on standard input. It does not actually consume
# a line, though.
if read -t 0; then
# Read standard input normally
while read line; do
echo $line
done
fi
# I'll assume you populate an array called input files
# while processing your arguments
for file in "${inputfiles[@]"; do
cat $file
done
Run Code Online (Sandbox Code Playgroud)
这是一个无意义的包装器,sort只是展示了将标准输入与其他输入文件组合的另一种方式:
if read -t 0; then
cat | sort fileA fileB
else
sort fileA file B
fi
Run Code Online (Sandbox Code Playgroud)
一个稍微有用的命令可能是sandwich,它在命令行上给出的两个文件之间输出其标准输入(如果有的话).
#!/bin/bash
cat "$1" # Output the first file
read -t 0 && cat # Pass through the standard input, if there is any
cat "$2" # Output the second file
# cat "$1" - "$2" is almost the same, but requires standard input.
Run Code Online (Sandbox Code Playgroud)
有些电话sandwich可能会
$ sandwich header.txt footer.txt
$ sandwich header.txt footer.txt < body.txt
$ cat chapter1.txt chapter2.txt | sandwich <(echo "My header") <(echo "My footer")
Run Code Online (Sandbox Code Playgroud)
这不太有用,所以还有改进的余地......
$ cat - | sandwich header.txt footer.txt
Run Code Online (Sandbox Code Playgroud)