2

我正在尝试在 sed 中使用 shell 通配符。以下失败。(我希望foo作为输出。)

$ touch foo
$ ls
foo
$ echo *
foo
$ bar=*
$ echo $bar
foo
$ echo "$bar"
*
$ echo replace | sed "s/replace/${bar}/"
*
$ echo replace | sed "s/replace/"${bar}"/"
*

正如预期的那样,倒数第二个命令不会产生foo,因为${bar}是(双)引号。但是,我希望最后一个命令扩展通配符。

不过,我可以让任一命令在以下之后工作。

bar=$(echo *)

此外,我预计下面的 shell 通配符扩展不会发生。

$ echo replace | sed s/replace/*/
*

但是,这行得通。

$ echo replace | sed s/replace/$(echo *)/
qwe
4

1 回答 1

3

您的最后一个命令确实尝试扩展通配符,但它失败了。来自man bash

 Pathname Expansion
        After  word  splitting,  unless  the -f option has been set, bash
        scans each word for the characters *, ?, and [.  If one of these
        characters appears, then the word is regarded as a pattern, and
        replaced with an alphabetically sorted list of file names matching
        the  pattern.

正如它所说,bash 尝试将包含 a 的每个单词扩展*为匹配的文件名。在您的情况下,它会尝试扩展为以开头的文件名s/replace/并且没有这样的文件。为了证明这一点:

$ echo "aaaa" | sed "s@a@*@g"
****

$ echo "aaaa" | sed "s@a@"*"@g"
****

$ touch s@a@b@g

$ echo "aaaa" | sed "s@a@*@g"
****

$ echo "aaaa" | sed "s@a@"*"@g"
bbbb

至于您的问题的解决方案,您可以使用评论中提到的子shell扩展。

于 2013-10-20T13:13:41.927 回答