![Shell 函数:管道序列作为参数](https://linux22.com/image/147194/Shell%20%E5%87%BD%E6%95%B0%EF%BC%9A%E7%AE%A1%E9%81%93%E5%BA%8F%E5%88%97%E4%BD%9C%E4%B8%BA%E5%8F%82%E6%95%B0.png)
我有一个 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")
的值(使用默认的单词拆分),然后用空格 ( )连接单词,将其作为输入传递到其中,并删除其中的任何单引号。$1
IFS
echo
sed
因此:
$ set -- "'foo bar'"
$ $(echo $1 | sed "s/'//g")
foo bar
命令中的外引号set
由 shell 处理,而内引号是值的一部分。请注意,这set -- 'foo bar'
不会导致$1
包含任何引号,这里唯一的引号将作为正常 shell 处理的一部分被删除。