Shell 函数:管道序列作为参数

Shell 函数:管道序列作为参数

我有一个 shell 函数(在 .bashrc 中),它创建一个临时文件,执行参数(包括所有管道序列),将其重定向到临时文件,然后在 VS Code 中打开它。

我调用 shell 函数为

Temp "ls | nl"

在下面的代码中,我尝试让它工作。我用 IFS 作为空格打破整个字符串,将其存储在数组中。现在我想执行整个管道序列并将最终的标准输出重定向到临时文件。我怎样才能实现这个目标?我知道 for 循环在这里不起作用。但我想打印整个数组。

Temp() {
    a="$(mktemp --suffix=.md "/tmp/$1-$(GetFilename "$2")-XXX")"
    IFS=' ' read -r -a Array <<< "$1"
    nArray=${#Array[@]} # Size of array
    for ((i=0; i<nArray; i=i+1)); do

    done
    #"${@}" > "$a"
    code -r "$a"
}

在交互式终端会话中,以下工作有效:

cat <<EOF
$(ls | nl)
EOF

所以,我尝试了 Heredoc,而不是函数内的 for 循环

cat > "$a" <<EOF
$($1)
EOF

但这会加上引号|,因此会失败。

如果我们能以某种方式删除引号,上面的方法就可以了。


这也行不通

cat > "$a" <<EOF
$(echo $1 | sed "s/'//g")
EOF

答案1

如果您希望函数执行作为参数给出的 shell 命令,则需要eval在字符串上使用,例如打印FOO

eval_arg() {
    eval "$1"
}
eval_arg "echo foo |tr a-z A-Z"

仅仅扩展"$1"是不行的,因为参数扩展后不会处理管道、引号和重定向等 shell 语法。将第一个参数拆分为数组或 to$@并不会真正改变这一点。


因此,$(ls | nl)有一个逐字管道字符,该字符在 shell 中进行处理,但在 中$($1),不会处理 值中的任何特殊字符$1(除了分词和通配符)。这里没有引号。

至于最后一个示例,拆分空白$(echo $1 | sed "s/'//g")的值(使用默认的单词拆分),然后用空格 ( )连接单词,将其作为输入传递到其中,并删除其中的任何单引号。$1IFSechosed

因此:

$ set -- "'foo  bar'"
$ $(echo $1 | sed "s/'//g")
foo bar 

命令中的外引号set由 shell 处理,而内引号是值的一部分。请注意,这set -- 'foo bar'不会导致$1包含任何引号,这里唯一的引号将作为正常 shell 处理的一部分被删除。

相关内容