3

我想编写一个 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)

我希望我的脚本能够以类似的方式处理参数和输入

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)

到目前为止,我只使用了“read”和“getopts”中的一些功能,并且认为如果我自己尝试这样做可能会出现问题。

为了让我更清楚地陈述我的问题,让 input.text 的内容为

aaa
bbb
ccc

我想使用参数 i 和 b 中的值来做一些事情,但我将在这个例子中打印出来。我想要的样本输出是

i : 3
b : 4
aaa
bbb
ccc

编写代码来处理上述示例命令以给出此输出的最佳方法是什么?

下面是从@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
4

2 回答 2

6

执行摘要:您可以read -t 0用来测试标准输入上是否有可用的输入。它将以状态 0 退出,数据在标准输入上立即可用(通过管道或重定向文件),如果没有,则为 1(例如,仍然连接到键盘)。然后,您可以根据是否需要从标准输入中读取来分支脚本。

if read -t 0; then
    # Do one thing
else
    # Do something else
fi

对我来说,棘手的部分是编写脚本,这样如果你不向它传递任何东西,它就不会阻止读取标准输入。

这似乎有效;欢迎改进。首先,在标准输入上消费所有内容;然后处理作为参数给出的文件。

# 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

这是一个毫无意义的包装器,sort只是演示了另一种将标准输入与其他输入文件相结合的方法:

if read -t 0; then
    cat | sort fileA fileB
else
    sort fileA file B
fi

一个稍微有用的命令可能是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.

一些电话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") 

这不太行,所以还有改进的余地......

$ cat - | sandwich header.txt footer.txt
于 2012-08-28T13:11:10.523 回答
0
cat input.txt | command
command < input.txt
command <(cat input.txt)

从应用程序的角度来看,这三个是相同的,shell 执行重定向。应用程序只需读取标准输入。

command input.txt
cat input.txt | command

这些仅在您处理的文件中有所不同,第一个是input.txt,第二个是标准输入,您可以使用它-,大多数 unix 命令都支持它。

# echo "X" | cat -
X

所以你设置了默认值:filename=-,如果你读取文件名选项,你会覆盖这个变量。

于 2012-08-28T13:03:26.237 回答