【问题标题】:How can I use a shell wildcard in sed?如何在 sed 中使用 shell 通配符?
【发布时间】:2013-10-20 10:57:10
【问题描述】:

我正在尝试在 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

【问题讨论】:

  • 那是因为 * 单独不是命令,但 echo * 是,shell 将 echo * 理解为命令并在 sed 开始工作后用它替换结果。
  • 你试过这个命令了吗?:echo replace | sed s/replace/$(echo ${bar})/(在子shell中启动echo,它的stdout进入你的sed命令)
  • @snyder 真的吗?但我并没有真正看到命令echo 和命令sed 之间的区别。同样,您可以在find 中使用* 等。我认为bash 总是会扩展。
  • @Gooseman 是的,这也有效。

标签: bash shell sed wildcard glob


【解决方案1】:

您的最后一个命令确实尝试扩展通配符,但它失败了。来自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 尝试将包含* 的每个单词扩展为匹配的文件名。在您的情况下,它会尝试扩展为以 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

至于你的问题的解决方法,你可以使用 cmets 中提到的 subshel​​l 扩展。

【讨论】:

  • 为了进一步演示,运行shopt -s nullglob,然后再次尝试上一条命令。当扩展失败时,sed 的整个参数将被删除,将您的命令保留为echo "aaaa" | sed,其中sed 只是复制其输入。
  • 很好的答案!非常清楚。此外,有趣的是,尽管有第一印象,但我提出的解决方案和 cmets 中的解决方案是对 echo 的无用使用。 (另外,感谢@chepner,这也很有趣。)
  • @Sparhawk bash 支持bar=*; foo=replace; echo "${foo/replace/$bar}",所以这里可能根本不需要sed
  • @chepner 我以前从未遇到过该变量内替换。它叫什么,所以我可以搜索更多并教育自己?但是,这似乎对我不起作用(即它输出 *)。
  • 这是一个bash 扩展,在bash 手册页的“参数扩展”下记录为“模式替换”。将参数引用到echo 可以防止* 在传递给echo 之前被扩展。取消引用它将允许 *echo 得到它之前展开。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-02-29
  • 2020-06-24
  • 2012-05-26
  • 2016-12-01
  • 2016-01-18
  • 1970-01-01
  • 2011-09-09
相关资源
最近更新 更多