问题描述
如何使用命令行查找和替换文本文件中的特定单词?
最佳解决办法
sed -i 's/original/new/g' file.txt
说明:
-
sed
=流式编辑器 -
-i
= in-place(即保存回原始文件) -
命令字符串:
-
s
=替代命令 -
original
=描述要替换的单词的正则表达式(或者仅仅是单词本身) -
new
=要替换的文本 -
g
=全局(即全部替换而不仅仅是第一次出现)
-
-
file.txt
=文件名
次佳解决办法
有很多不同的方法可以做到这一点。一种是使用sed
和Regex。 SED是用于过滤和转换文本的流编辑器。一个例子如下:
marco@imacs-suck: ~$ echo "The slow brown unicorn jumped over the hyper sleeping dog" > orly
marco@imacs-suck: ~$ sed s/slow/quick/ < orly > yarly
marco@imacs-suck: ~$ cat yarly
The quick brown unicorn jumped over the hyper sleeping dog
另一种比< strin
和> strout
更有意义的方法是使用管道!
marco@imacs-suck: ~$ cat yarly | sed s/unicorn/fox/ | sed s/hyper/lazy/ > nowai
marco@imacs-suck: ~$ cat nowai
The quick brown fox jumped over the lazy sleeping dog
第三种解决办法
通过awk的gsub命令,
awk '{gsub(/pattern/,"replacement")}' file
例:
awk '{gsub(/1/,"0");}' file
在上面的例子中,所有的1被0替换,而不管它所在的列。
如果你想在特定的列上做一个替换,那么就这样做,
awk '{gsub(/pattern/,"replacement",column_number)}' file
例:
awk '{gsub(/1/,"0",$1);}' file
它仅在第1列上用0代替1。
通过Perl,
$ echo 'foo' | perl -pe 's/foo/bar/g'
bar
第四种办法
您可以在Ex模式下使用Vim:
ex -sc '%s/OLD/NEW/g|x' file
-
%
选择所有行 -
s
替代品 -
g
替换每行中的所有实例 -
x
写入是否有更改(他们有)并退出
第五种办法
有很多方法可以实现它。取决于用串替换实现的复杂性以及取决于用户熟悉的工具,一些方法可能比其他方法更受欢迎。
在这个答案中,我使用了简单的input.txt
文件,您可以使用它来测试此处提供的所有示例。文件内容:
roses are red , violets are blue
This is an input.txt and this doesn't rhyme
BASH
Bash并非真正用于文本处理,而是简单的替换可以通过parameter expansion完成,特别是在这里我们可以使用简单的结构${parameter/old_string/new_string}
。
#!/bin/bash
while IFS= read -r line
do
case "$line" in
*blue*) printf "%s\n" "${line/blue/azure}" ;;
*) printf "%s\n" "$line" ;;
esac
done < input.txt
这个小脚本不会执行in-place替换,这意味着您将不得不将新文本保存到新文件中,并删除旧文件或mv new.txt old.txt
注意:如果您对使用while IFS= read -r ; do ... done < input.txt
的原因感到好奇,它基本上是shell逐行读取文件的方式。请参阅this以供参考。
AWK
作为文本处理工具的AWK非常适合这样的任务。它可以做简单的替换和基于regular expressions的更先进的替换。它提供了两个功能:sub()
和gsub()
。第一个只替换第一个事件,而第二个替换整个字符串中的事件。例如,如果我们有字符串one potato two potato
,这将是结果:
$ echo "one potato two potato" | awk '{gsub(/potato/,"banana")}1'
one banana two banana
$ echo "one potato two potato" | awk '{sub(/potato/,"banana")}1'
one banana two potato
AWK可以将一个输入文件作为参数,因此使用input.txt
做同样的事情很简单:
awk '{sub(/blue/,"azure")}1' input.txt
根据您拥有的AWK版本,它可能会或可能不会有in-place编辑,因此通常的做法是保存并替换新文本。比如像这样的东西:
awk '{sub(/blue/,"azure")}1' input.txt > temp.txt && mv temp.txt input.txt
SED
Sed是行编辑器。它也使用正则表达式,但对于简单的替换就足够了:
sed 's/blue/azure/' input.txt
这个工具的好处在于它具有in-place编辑功能,您可以使用-i
标志启用它。
Perl
Perl是经常用于文本处理的另一种工具,但它是一种通用语言,用于网络,系统管理,桌面应用程序和许多其他地方。它从C,sed,awk等其他语言借用了很多概念/特性。简单的替换可以这样完成:
perl -pe 's/blue/azure/' input.txt
像sed一样,perl也有-i标志。
Python
这种语言非常灵活,也用于各种各样的应用程序。它有很多用于处理字符串的函数,其中有replace()
,所以如果你有像var="Hello World"
这样的变量,你可以做var.replace("Hello","Good Morning")
简单的读取文件和替换字符串的方法如下:
python -c "import sys;lines=sys.stdin.read();print lines.replace('blue','azure')" < input.txt
但是,对于Python,您还需要输出到新文件,您也可以在脚本中执行该文件。例如,这是一个简单的例子:
#!/usr/bin/env python
import sys
import os
import tempfile
tmp=tempfile.mkstemp()
with open(sys.argv[1]) as fd1, open(tmp[1],'w') as fd2:
for line in fd1:
line = line.replace('blue','azure')
fd2.write(line)
os.rename(tmp[1],sys.argv[1])
此脚本将作为命令行参数与input.txt
一起调用。
Python也可以有正则表达式,特别是re
模块,它具有re.sub()
功能,可用于更高级的替换。
第六种办法
sed
是流编辑器,因为您可以使用|
(管道)通过sed
发送标准流(STDIN和STDOUT),并通过编程方式实时更改它们,使其成为Unix哲学传统中的便捷工具;但也可以使用下面提到的-i
参数直接编辑文件。考虑以下:
sed -i -e 's/few/asd/g' hello.txt
s/
用于用asd
替代找到的表达式few
:
The few, the brave.
The asd, the brave.
/g
代表”global”,意思是为整条生产线做这件事。如果您离开/g
(使用s/few/asd/
,无论如何都始终需要三个斜杠),并且few
在同一行上出现两次,只有第一个few
更改为asd
:
The few men, the few women, the brave.
The asd men, the few women, the brave.
这在某些情况下很有用,例如在行首改变特殊字符(例如,替换greater-than符号,有些人用水平制表符引用电子邮件线索中的前一个素材,而在行后面留下引用的代数不等式) ,但在你的例子中,你指定的地方few
发生时应该被替换,确保你有那个/g
。
以下两个选项(标志)合并为一个,-ie
:
-i
选项用于在文件hello.txt
上进行编辑。
-e
选项指示要运行的表达式/命令,在这种情况下为s/
。
注意:使用-i -e
进行搜索/替换非常重要。如果您执行-ie
,则为每个附加了字母’e’的文件创建一个备份。