替换文本文件 ** 不带** 正则表达式

And*_*rea 97 text-editing bash regex sed

我需要用替换来替换文本文件中的一些文本。通常我会做类似的事情

sed -i 's/text/replacement/g' path/to/the/file
Run Code Online (Sandbox Code Playgroud)

问题是textreplacement都是包含破折号、斜线、黑斜线、引号等的复杂字符串。如果我转义所有必要的字符text,东西很快就会变得不可读。另一方面,我不需要正则表达式的强大功能:我只需要按字面意思替换文本即可。

有没有办法在使用某些 bash 命令的正则表达式的情况下进行文本替换?

编写一个执行此操作的脚本会相当简单,但我认为应该已经存在一些东西。

nik*_*nik 17

当您不需要正则表达式的强大功能时,请不要使用它。那没关系。
但是,这并不是真正的正则表达式

sed 's|literal_pattern|replacement_string|g'
Run Code Online (Sandbox Code Playgroud)

因此,如果/是您的问题,请使用|并且您无需逃避前者。

PS:关于评论,另请参阅有关Escape a string for sed search pattern 的Stackoverflow 答案。


更新:如果你能很好地使用Perl试试看\Q\E像这样,

 perl -pe 's|\Qliteral_pattern\E|replacement_string|g'
Run Code Online (Sandbox Code Playgroud)

@RedGrittyBrick 在此处此处的评论中也提出了类似的具有更强 Perl 语法的技巧

  • 我不确定这个答案是否有用...... `s|||` 和 `s///` 之间的唯一区别是分隔符不同,因此 **one** 字符不需要转义. 你同样可以做`s###`。这里真正的问题是 OP 不想担心转义 `literal_pattern` 的内容(它根本不是文字,将被解释为正则表达式)。 (80认同)
  • 这个答案不应该*被接受 (31认同)
  • 这不会避免其他特殊字符的解释。如果使用您的解决方案搜索 `1234.*aaa`,它会比预期的 `1234\.\*aaa` 匹配得多。 (20认同)
  • 这完全没有抓住重点。要匹配的文本可以包含任何奇怪的内容。就我而言,它是一个随机密码。你知道这些是怎么回事 (6认同)
  • 我同意史蒂文·卢的观点,因为这是完全错误的。 “s/aaa/bbb/”中“s”之后的第一个字符只是一个任意分隔符,可以是任何内容,只要它不出现在 aaa 或 bbb 中即可。这三个给出完全相同的结果,并且“aaa”*总是*被 sed 解释为正则表达式:“s/aaa/bbb/”、“s|aaa|bbb|”,甚至“scaaacbbbc”。 https://www.gnu.org/software/sed/manual/sed.html#The-_0022s_0022-命令 (3认同)

Now*_*ker 16

export FIND='find this'
export REPLACE='replace with this'
ruby -p -i -e "gsub(ENV['FIND'], ENV['REPLACE'])" path/to/file
Run Code Online (Sandbox Code Playgroud)

这是这里唯一 100% 安全的解决方案,因为:

  • 这是一个静态替换,而不是正则表达式,不需要转义任何东西(因此,优于 using sed
  • 如果您的字符串包含}字符,它不会中断(因此,优于提交的 Perl 解决方案)
  • 它不会与任何字符中断,因为ENV['FIND']使用的是,而不是$FIND. 使用$FINDRuby 代码内联的 或 您的文本,如果您的字符串包含未转义的'.


Der*_*eit 11

replace命令将执行此操作。

https://linux.die.net/man/1/replace

原地变化:

replace text replacement -- path/to/the/file
Run Code Online (Sandbox Code Playgroud)

到标准输出:

replace text replacement < path/to/the/file
Run Code Online (Sandbox Code Playgroud)

例子:

$ replace '.*' '[^a-z ]{1,3}' <<EOF
> r1: /.*/g
> r2: /.*/gi
> EOF
r1: /[^a-z ]{1,3}/g
r2: /[^a-z ]{1,3}/gi
Run Code Online (Sandbox Code Playgroud)

replace命令随 MySQL 或 MariaDB 提供。

  • @masterxilo 一个更好的问题可能是——为什么现代操作系统没有这样一个基本命令?;-) (12认同)
  • 考虑到 tht replace 已被弃用并且将来可能不会被弃用 (3认同)
  • 为什么这样的基本命令会带有数据库? (3认同)
  • 我安装了 MariaDB,“cp /usr/bin/replace ~/.local/bin”(在 $PATH 中),然后将其卸载。 (3认同)

Vas*_*kov 7

您可以自动将模式转换为其转义形式。像这样:

keyword_raw=$'1\n2\n3'
keyword_regexp="$(printf '%s' "$keyword_raw" | sed -e 's/[]\/$*.^|[]/\\&/g' | sed ':a;N;$!ba;s,\n,\\n,g')"
# keyword_regexp is now '1\/2\/3'

replacement_raw=$'2\n3\n4'
replacement_regexp="$(printf '%s' "$replacement_raw" | sed -e 's/[\/&]/\\&/g' | sed ':a;N;$!ba;s,\n,\\n,g')"
# replacement_regexp is now '2\/3\/4'

echo $'a/b/c/1\n2\n3/d/e/f' | sed -e "s/$keyword_regexp/$replacement_regexp/"
# the last command will print 'a/b/c/2\n3\n4/d/e/f'
Run Code Online (Sandbox Code Playgroud)

该解决方案的积分如下: /sf/ask/28526641/

注意1:这只适用于非空关键字。sed ( ) 不接受空关键字sed -e 's//replacement/'

注2:不幸的是,我不知道有哪个流行工具不会使用 regexp-s 来解决问题。您可以用 Rust 或 C 编写这样的工具,但默认情况下不存在。

  • 这完全没有抓住OP的要点。显然你可以逃避该模式,但对于某些模式来说这是乏味的。 (6认同)