Sed替换不适用于shell变量

时间:2017-11-04 15:29:59

标签: bash

我使用sed替换所有文件中的字符串。

我有这个,但它确实有效:

#!/bin/bash
OLD="oldtext"
NEW="newtext"

grep -rli '$OLD' * | xargs -i@ sed -i 's/$OLD/$NEW/g' @

但是这个

grep -rli 'oldtext' * | xargs -i@ sed -i 's/oldtext/newtext/g' @

作品!我该如何修理我的命令?

1 个答案:

答案 0 :(得分:0)

正如randomir的评论及其链接的问题所指出的,你必须使用双引号,以便扩展变量:

old="oldtext"
new="newtext"
grep -rZli "$old" | xargs -0 sed -i "s/$old/$new/gi"

我也改变了其他一些事情:

  • 小写变量名称,以避免与为环境变量保留的名称冲突
  • grep -Z选项将文件名与NUL字节分开以处理特殊字符,例如文件名中的换行符
  • 在sed模式之后跳过*,因为它默认为工作目录
  • -0选项让xargs期望NUL字节分隔的文件名
  • 跳过(已弃用)-i选项,因为文件名无论如何都会转到命令的末尾
  • i标记,用于匹配grep命令中不区分大小写匹配的替换

其中一些需要GNU grep,xargs和sed。

如果您没有查看大量文件以证明首先使用它们,那么您可以使用通用的**/* glob来对它们进行单个sed进程:

shopt -s globstar
sed -i "s/$old/$new/gi" **/*

这会抱怨sed试图在目录上运行,但它并没有受到伤害;如果您的所有文件都有.txt之类的公共扩展名,则可以使用**/*.txt来避免这种情况。

另一方面,如果您有大量文件并且想要加速任务,则可以使用xargs的-P选项进行并行化:

grep -rZli "$old" | xargs -0 -P 4 sed -i "s/$old/$new/gi"

用于四个并行流程。