使用| $ variable中的竖线字符使它成为bash中的另一个参数;如何逃脱呢?


8

我有一个这样的bash脚本

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

但是它给出了错误

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

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

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

我试图有条件地设置$pipedargument。我想我可以有条件地执行命令的不同版本,但仍然想知道是否有办法使上述工作正常进行?

Answers:


9

没错,您不能使用|这种方式。原因是外壳程序在进行变量替换之前已经在寻找管道并将它们分成命令。因此,|被视为另一个字符。

一种可能的解决方法是按原样放置管道字符:

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

如果您不想使用管道,则可以将其cat用作“ nop”或占位符:

$ cmd=cat
$ ls | $cmd

这种方法避免了eval微妙之处。另请参阅此处

更好的方法:数组

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

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

一旦需要命令cmd包含引号的参数,数组的优势就变得很重要。


您能否弄清楚为什么在引用参数的情况下需要数组?我遇到了,但是不太明白为什么它不起作用。
anxieux

@anxieux一个简短的答案是, shell字符串中使用引号时,会失去所有将单词分组的句法功能,而是像其他任何字符一样被处理。有关此问题的详细讨论,请参见:我试图将命令放入变量中,但是复杂的情况总是会失败!
John1024 '17

5

您可以使用eval以下命令:

eval "ls $pipedargument"

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

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

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

sorted ls /tmp

另一个选择是定义别名:alias ls='ls | sort -n'
thiagowfx 2015年

0

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

### 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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.