为什么这不起作用?
$ s="-e 's/^ *//' -e 's/ *$//'"
$ ls | sed $s
sed: 1: "'s/^
": invalid command code '
$ ls | gsed $s
gsed: -e expression #1, char 1: unknown command: `''
但这样做:
$ ls | eval sed $s
... prints staff ...
$ ls | eval gsed $s
... prints staff ...
尝试从$ s中删除单引号,但它仅适用于没有空格的模式:
$ s="-e s/a/b/"
$ ls | sed $s
... prints staff ...
$ s="-e s/^ *//"
$ ls | sed $s
sed: 1: "s/^
": unterminated substitute pattern
或
$ s="-e s/^\ *//"
$ ls | sed $s
sed: 1: "s/^\
": unterminated substitute pattern
Mac OS 10.8,bash 4.2,Mac端口默认sed和gsed 4.2.2
答案 0 :(得分:2)
简单的问题和复杂的答案。大部分问题都与shell有关; sed
只是部分问题。 (换句话说,您可以使用许多不同的命令而不是sed
,并会遇到类似的问题。)
请注意,当参数字符串附加到选项时,大多数使用选项字母和单独的参数字符串记录的命令也将起作用。例如:
sort -t :
sort -t:
这两个都为:
选项提供值-t
。与sed
和-e
选项类似。也就是说,你可以写下以下任何一个:
sed -n -e /match/p
sed -n -e/match/p
让我们看一下您编写的sed
命令之一:
$ s="-e s/a/b/"
$ ls | sed $s
这里传递的sed
命令是两个参数(在它的命令名之后):
-e
s/a/b/
这是sed
的完美参数集。那么第一个出了什么问题呢?
$ s="-e 's/^ *//' -e 's/ *$//'"
$ ls | sed $s
嗯,这次,sed
命令传递了6个参数:
-e
's/^
*//'
-e
's/
*$//'
您可以使用al
命令(参数列表 - 在各自的行上打印每个参数;在本答案的底部对其进行描述和实现),以查看如何向sed
显示参数。只需在示例中键入al
代替sed
。
现在,-e
选项后跟一个有效的sed
命令,但's/^
不是有效命令;引用'
不是有效的sed
命令。在shell提示符下键入命令时,shell会处理单引号并将其删除,因此sed
通常不会看到它,但这会在shell变量展开之前发生。
然后,为什么eval
可以工作:
$ s="-e 's/^ *//' -e 's/ *$//'"
$ ls | eval sed $s
eval
重新评估命令行。它看到了:
eval sed -e 's/$ *//' -e 's/ *$//'
并完成整个评估过程。它会在对字符进行分组后删除单引号,因此sed
会看到:
-e
s/$ *//
-e
s/ *$//
这是完全有效的sed
脚本。
您的一项测试是:
$ s="-e s/^ *//"
$ ls | sed $s
这失败了因为sed
被赋予了参数:
-e
s/^
*//
第一个不是有效的替代命令,第二个不太可能是有效的文件名。有趣的是,你可以通过在$s
周围加上双引号来解决这个问题,如:
$ s="-e s/^ *//"
$ ls | sed "$s"
现在sed
获得一个参数:
-e s/^ *//
但是-e
可以附加命令,并且命令的前导空格被忽略,所以这一切都是有效的。但是,第一次尝试不能这样做:
$ s="-e 's/^ *//' -e 's/ *$//'"
$ ls | sed "$s"
现在您被告知'
未被识别。但是,您可以使用:
$ s="-e s/^ *//; s/ *$//"
$ ls | sed "$s"
同样,sed
看到一个参数,并且sed
选项的参数中有两个以分号分隔的-e
命令。
你可以从这里响起变化。我发现al
命令非常有用;它经常帮助我理解哪里出了问题。
al
的来源 - 参数列表#include <stdio.h>
int main(int argc, char **argv)
{
while (*++argv)
puts(*argv);
return 0;
}
这是你可以编写的最小的有用C程序之一('hello world'缩短了一行,但除了演示如何编译和运行程序之外,它没什么用处)。它自己在一行上列出每个参数。您还可以使用bash
命令在printf
和其他相关shell中模拟它:
printf "%s\n" "$@"
将其包裹为一个功能:
al()
{
printf "%s\n" "$@"
}
答案 1 :(得分:0)
sed适用于您的正常替换模式,因为它没有任何元字符。你只有a和b。当涉及元字符时,您需要单引号。
我认为sed只能通过使用eval来正常工作。