在Bash中动态构建命令管道

时间:2018-09-27 14:02:31

标签: bash variables command

我正在编写一个带有选项的bash程序。

例如:./my_program -l 3 -a -s

  • -l 3将输出限制为三行
  • -a将选择我的所有文件
  • -s将对输出进行排序

就目前而言,我可以一次使用两个选项:

if [ $all == 1 ]
then
    if [ $sort == 1 ]
    then
        printf '%s\n' "${haikus[@]}" | sed -e 's/^[ \t]*//' | sort
    else
        printf '%s\n' "${haikus[@]}" | sed -e 's/^[ \t]*//'
    fi
fi

如果使用-a选项,则打印整个文件;如果使用-a选项和-s选项,则使用相同的命令,但是使用sort

使用这种解决方案,如果我想实现-l,它将创建很多“ if”语句。

我首先想到创建一个包含命令的变量。

示例:

sort='sort'
limit='grep -m3'

然后以这种方式编写我的命令:

printf '%s\n' "${haikus[@]}" | sed -e 's/^[ \t]*//' | $sort | $limit

但这根本行不通。

事实是,我想编写一个基本命令,并能够根据选项添加更多命令。

在没有大量“ if”语句的情况下如何正确执行此操作?

4 个答案:

答案 0 :(得分:2)

一个棘手的问题,不太明显的解决方案。

您可以做的是将几个函数调用链接在一起。这些功能可以检查相关标志,然后“执行某些操作”(如调用sort)或“不执行任何操作”,然后仅调用cat。在管道中进行简单的cat调用本质上是无操作的:它将stdin不变地复制到stdout。

maybe_sort() {
    if [[ $sort == 1 ]]; then
        sort
    else
        cat
    fi
}

maybe_limit() {
    if [[ -n $limit ]]; then
        head -n "$limit"
    else
        cat
    fi
}

要使用这些内容,请输入:

printf '%s\n' "${haikus[@]}" | sed -e 's/^[ \t]*//' | maybe_sort | maybe_limit

答案 1 :(得分:2)

您可以直接通过管道传递到if语句。不过,在某些地方,这将需要像cat这样的无操作滤镜,因此在这方面效率稍低。

printf '%s\n' "${haikus[@]}" | sed -e 's/^[ \t]*//' |
 if [ "$sort" = 1 ]; then sort; else cat; fi |
 if [ "$l" -gt 0 ]; then grep -m"$l"; else cat; fi

if语句本身就是命令,因此它具有自己的文件描述符集,这些文件描述符是随附命令继承的。 if语句本身不使用这些描述符进行任何操作,因此sortcat都可以查看未包装的数据第一名。

答案 2 :(得分:0)

好的,大家好。我迟到了。我不知道我可以将cat用作不操作对象,而这正是我寻求的解决方案。 因此,我仅使用“ cat” op初始化了所有选项。如果正确触发了该选项,则只需使用良好的操作来更新字符串。 然后,我只需要编写一条包含所有选项的操作行即可。

非常感谢您。

答案 3 :(得分:0)

我正在寻找没有固定顺序的解决方案。结束于:

# assemble pipeline from sequence of arguments
# each argument interpreted as command to evaluate (e.g. spaces interpreted)
pipe_all() {
    if [[ $# -gt 0 ]]; then
        local current=$1
        shift
        eval "$current" | pipe_all "$@"
    else
        cat
    fi
}

filter_weapon() {
    grep '/Weapon/'
}

filters=()
filters+=(sort)
filters+=(uniq)
filters+=(filter_weapon)
filters+=("head -n $1")  # should be encoded as a single argument and be a valid command

pipe_all "${filters[@]}"