使用| $variable 中的管道字符使其被视为 bash 中的另一个参数;如何逃脱呢?

使用| $variable 中的管道字符使其被视为 bash 中的另一个参数;如何逃脱呢?

我有一个像这样的 bash 脚本

export pipedargument="| sort -n"
ls $pipedargument

但它给出了错误

ls: |: No such file or directory
ls: sort: No such file or directory

它似乎将 的内容视为"| sort -n"传递给 的参数ls

我如何转义它以便将其视为常规管道命令?

我正在尝试有条件地设置$pipedargument.我想我可以有条件地执行不同版本的命令,但仍然想知道是否有办法让这个工作像上面一样?

答案1

你是对的,你不能用|这种方式。原因是 shell 在执行变量替换之前已经查找管道并将它们分成命令。因此,|被视为只是另一个字符。

一种可能的解决方法是将管道字符按字面意思放置:

$ cmd="sort -n"
$ ls | $cmd

如果您不需要管道,可以用作cat“nop”或占位符:

$ cmd=cat
$ ls | $cmd

该方法避免了评估的微妙之处。也可以看看这里

更好的方法:数组

更复杂的方法是使用bash数组代替普通字符串:

$ cmd=(sort -n)
$ ls | "${cmd[@]}"

当您需要命令cmd包含带引号的参数时,数组的优点就变得很重要。

答案2

您可以eval使用以下命令:

eval "ls $pipedargument"

甚至更好地定义函数,例如:

sorted() { "$@" | sort -n; }

然后用所需的参数调用它:

sorted ls /tmp

答案3

我会为此使用一个函数。就像是:

### usage pipedargument cmd args ###

pipedargument()
{
    sort -n <<< "$( "$@" )"
}

$ pipedargument /sbin/ifconfig eth0
      RX bytes:5904986765 (5.4 GiB)  TX bytes:714370767 (681.2 MiB)
      RX packets:5981427 errors:0 dropped:0 overruns:0 frame:0
      TX packets:4403989 errors:0 dropped:0 overruns:0 carrier:0
      UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
      collisions:0 txqueuelen:1000 
      inet addr:XXX.XXX.X.XX  Bcast:XXX.XXX.X.XXX  Mask:255.255.255.0
      inet6 addr: xx00::0x0x:00xx:xx0:000/00 Scope:Link
eth0      Link encap:Ethernet  HWaddr 0x:0x:00:x0:00:00

相关内容