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


68

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

sed -i 's/text/replacement/g' path/to/the/file

问题在于,两者textreplacement都是包含破折号,斜杠,黑斜杠,引号等的复杂字符串。如果我逃避了所有必要的字符text,事情就会很快变得不可读。另一方面,我不需要正则表达式的功能:我只需要逐字替换文本即可。

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

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


有必要通过bash做到吗?一个简单的解决方案是在Word中打开并执行find and replace all
Akash 2012年

17
@akash因为系统bash始终与Microsoft Word一起提供?;) 不仅仅在开玩笑。OP可能希望在远程计算机上或一批文件中执行此操作。
slhck 2012年

@slhck :)好吧,我想gedit应该有一个类似的选择
Akash

一种选择是在将所有内容传递给之前以某种方式正确地对其进行转义sed,考虑到所有开关和平台的差异,这可能是徒劳的。
l0b0 2012年

Answers:


6

当您不需要正则表达式的功能时,请不要使用它。那也行。
但是,这并不是真正的正则表达式

sed 's|literal_pattern|replacement_string|g'

因此,如果/|遇到了问题,请使用,而无需逃脱前者。

ps:关于评论,另请参阅关于为sed搜索模式转义字符串的 Stackoverflow答案。


更新:如果您使用Perl很好,请尝试使用\Q\E像这样,
perl -pe 's|\Qliteral_pattern\E|replacement_string|g'
RedGrittyBrick并在此处的注释中还提出了类似的技巧,其中包含更强大的Perl语法


谢谢,我不知道/和|之间的区别。
安德里亚(Andrea)2012年

64
我不确定此答案是否有用... s|||和之间的唯一区别s///是分隔符不同,因此一个字符不需要转义。你同样可以做s###。真正的问题是,OP不必担心转义的内容literal_pattern(根本不是字面意义,并且将被解释为正则表达式)。
Benj 2012年

15
这将避免避免解释其他特殊字符。如果1234.*aaa用您的解决方案进行搜索会比预期的匹配得多1234\.\*aaa
Matteo

20
这个答案应该被接受
史蒂芬路

2
这完全错过了重点。要匹配的文本可能包含任何怪味。就我而言,这是一个随机密码。你知道那是怎么回事
Christian Bongiorno

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

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

  • 这是一个静态替换,而不是正则表达式,无需转义任何内容(因此,优于使用sed
  • 如果您的字符串包含}char,它不会中断(因此,优于提交的Perl解决方案)
  • 它不会与任何字符分开,因为ENV['FIND']已使用而不是$FIND。使用$FIND或将您的文本插入Ruby代码,如果您的字符串包含未转义的,则可能会遇到语法错误'

我必须export FIND='find this; export REPLACE='replace with this';在我的bash脚本中使用它,ENV['FIND']ENV['replace']具有期望的值。我正在替换文件中一些很长的加密字符串。这只是票。
DMfll

这是一个很好的答案,因为它可靠且红宝石无处不在。基于此答案,我现在使用此shell脚本
loevborg

不幸的是,当FIND包含多行时,它不起作用。
adrelanos

没有什么可以阻止它在FIND中使用多行。使用双引号\ n。
Nowaker

7

replace命令将执行此操作。

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

更改位置:

replace text replacement -- path/to/the/file

要输出:

replace text replacement < path/to/the/file

例:

$ replace '.*' '[^a-z ]{1,3}' <<EOF
> r1: /.*/g
> r2: /.*/gi
> EOF
r1: /[^a-z ]{1,3}/g
r2: /[^a-z ]{1,3}/gi

replace命令随MySQL或MariaDB一起提供。


3
考虑到替换已被弃用,将来可能不承担责任
Rogelio

1
为什么这样的基本命令随数据库一起提供?
masterxilo

3
@masterxilo一个更好的问题可能是-为什么现代操作系统没有这样的基本命令?;-)
马克·汤姆森



2

您可以通过转义样式来做到这一点。像这样:

keyword_raw='1/2/3'
keyword_regexp="$(printf '%s' "$keyword_raw" | sed -e 's/[]\/$*.^|[]/\\&/g')"
# keyword_regexp is now '1\/2\/3'

replacement_raw='2/3/4'
replacement_regexp="$(printf '%s' "$replacement_raw" | sed -e 's/[\/&]/\\&/g')"
# replacement_regexp is now '2\/3\/4'

echo 'a/b/c/1/2/3/d/e/f' | sed -e "s/$keyword_regexp/$replacement_regexp/"
# the last command will print 'a/b/c/2/3/4/d/e/f'

这种解决方案的功劳可以在这里找到:https : //stackoverflow.com/questions/407523/escape-a-string-for-a-sed-replace-pattern

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

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


这完全错过了OP的观点。显然,您可以逃脱该模式,但是对于某些模式而言,这是乏味的。
icecreamsword

@icecreamsword您是否在第一行下方阅读了我的答案?该脚本会自动转义。
VasyaNovikov '18 -10-3

1

我拼凑了其他一些答案,并提出了以下建议:

function unregex {
   # This is a function because dealing with quotes is a pain.
   # http://stackoverflow.com/a/2705678/120999
   sed -e 's/[]\/()$*.^|[]/\\&/g' <<< "$1"
}
function fsed {
   local find=$(unregex "$1")
   local replace=$(unregex "$2")
   shift 2
   # sed -i is only supported in GNU sed.
   #sed -i "s/$find/$replace/g" "$@"
   perl -p -i -e "s/$find/$replace/g" "$@"
}

不适用于换行符。也不利于使用来换行\n。有什么办法吗?
adrelanos

1

您可以使用php的str_replace

php -R 'echo str_replace("\|!£$%&/()=?^\"'\''","replace",$argn),PHP_EOL;'<input.txt >output.txt

注意:不过,您仍然需要转义单引号'和双引号"


0

相当于@Nowaker的Node.JS:

export FNAME='moo.txt'
export FIND='search'
export REPLACE='rpl'
node -e 'fs=require("fs");fs.readFile(process.env.FNAME,"utf8",(err,data)=>{if(err!=null)throw err;fs.writeFile(process.env.FNAME,data.replace(process.env.FIND,process.env.REPLACE),"utf8",e=>{if(e!=null)throw e;});});'

0

这是另一种“几乎”工作方式。

使用vi或vim。

创建一个包含替换内容的文本文件:

:%sno /我的搜索字符串\\“-:#2; g('。j'); \\”> /我的replacestring = \\“ bac)(o:#46; \\”> /
:X

然后从命令行执行vi或vim:

vi -S commandfile.txt path/to/the/file

:%sno是vi命令,可以在没有魔术的情况下进行搜索和替换。

/是我选择的分隔符。

:x保存并退出vi。

您需要转义反斜杠'\',反斜杠'/'可能会替换为问号'?'。或不在您的搜索或替换字符串中的其他内容,请使用管道“ |” 对我不起作用

参考:https : //stackoverflow.com/questions/6254820/perform-a-non-regex-search-replace-in-vim https://vim.fandom.com/wiki/Search_without_need_to_escape_slash http://linuxcommand.org/ lc3_man_pages / vim1.html

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.