如何替换多个文本文件的第5行上的字符串?
我想使用单个终端命令将字符串“Good Morning”替换为多个文本文件的第5行( file1.txt,file2.txt,file3.txt,file4.txt )。
所有文本文件都位于我的~/Desktop
。
注意:我的桌面包含6个.txt文件。我想将更改仅应用于上述4个文本文件。
以下是一些方法。 我正在使用大括号扩展 ( file{1..4}.txt
),这意味着file1.txt file2.txt file3.txt file4.txt
-
Perl的
perl -i -pe 's/.*/ Good Morning / if $.==5' file{1..4}.txt
说明:
-
-i
:使perl
编辑文件,更改原始文件。如果
-i
后跟文件扩展名后缀,则会为每个已修改的文件创建备份。 例如:如果在执行期间修改了file1.txt.bak
则-i.bak
会创建file1.txt.bak
。 -
-p
:表示逐行读取输入文件,应用脚本并打印。 -
-e
:允许您从命令行传递脚本。 -
s/.*/ Good Morning /
:那将用s/.*/ Good Morning /
取代当前行(.*
)中的文字。 -
$.
是一个特殊的Perl变量,它保存输入文件的当前行号。 所以,s/foo/bar/ if $.==5
,表示仅在第5行用bar
替换foo
。
-
-
SED
sed -i '5s/.*/ Good Morning /' file{1..4}.txt
说明:
-
-i
:与perl
一样,编辑文件到位。
默认情况下,
sed
打印输入文件的每一行。5s/pattern/replacement/
表示在第5行替换替换模式。 -
-
AWK
for f in file{1..4}.txt; do awk 'NR==5{$0=" Good Morning "}1;' "$f" > foobar && mv foobar "$f"; done
说明:
awk
没有等同于-i
选项¹,这意味着我们需要创建一个临时文件(foobar
),然后重命名该文件以覆盖原始文件。for f in file{1..4}.txt; do ... ; done
的bash循环for f in file{1..4}.txt; do ... ; done
for f in file{1..4}.txt; do ... ; done
for f in file{1..4}.txt; do ... ; done
只需浏览file{1..4}.txt
每一个,将当前文件名保存为$f
。 在awk
,NR
是当前行号,$0
是当前行的内容。 因此,该脚本将仅在第5行用“早安”替换该行($0
)。1;
是“打印线”的awk
。¹ 较新的版本就像devnull在他的回答中所表现的那样。
-
的coreutils
for f in file{1..4}.txt; do (head -4 "$f"; echo " Good Morning "; tail -n +6 "$f") > foobar && mv foobar "$f"; done
说明:
循环在前一节中解释。
-
head -4
:打印前4行 -
echo " Good Morning "
:打印“早安” -
tail -n +6
:打印从第6行到文件末尾的所有内容
围绕这三个命令的括号
( )
允许您捕获所有三个命令的输出(因此,前4行,然后是“早上好”,然后是其余行)并将它们重定向到文件。 -
你可以使用sed
:
sed '5s/^/Good morning /' file
会在文件的第五行附上Good morning
。
如果你想替换第5行的内容,请说:
sed '5s/.*/Good morning/' file
如果要将更改保存到文件,请使用-i
选项:
sed -i '5s/.*/Good morning/' file
sed
可以一次处理多个文件。 您只需在命令末尾添加更多文件名即可。 您还可以使用bash扩展来匹配特定文件:
# manually specified sed -i '5s/.*/Good morning/' file1.txt file2.txt file3.txt file4.txt # wildcard: all files on the desktop sed -i '5s/.*/Good morning/' ~/Desktop/* # brace expansion: file1.txt, file2.txt, file3.txt, file4.txt sed -i '5s/.*/Good morning/' file{1..4}.txt
你可以在这里阅读更多关于大括号扩展的内容 。
GNU awk 4.1.0及更高版本附带了一个支持就地编辑的扩展 。 所以你可以说:
gawk -i inplace 'NR==5{$0="Good morning"}7' file
用Good morning
!取代文件中的第5行!
我没有看到python解决方案,所以这里是:
import sys import os def open_and_replace(filename): with open(filename) as read_file: temp = open("/tmp/temp.txt","w") for index,line in enumerate(read_file,1): if index == 5: temp.write("NEW STRING\n") else: temp.write(line.strip() + "\n") temp.close() os.rename("/tmp/temp.txt",filename) for file_name in sys.argv[1:]: open_and_replace(file_name)
基本思想是,对于命令行中提供的每个文件作为参数,我们写出一个临时文件并枚举原始文件中的每一行。 如果该行的索引是5,我们写出不同的行。 剩下的就是用临时文件Demo替换旧文件:
$> ls file1.txt file2.txt file3.txt $> cat file1.txt line 1 line 2 line 3 line 4 GOOD MORNING line 6 $> python ~/replace_5th_line.py file1.txt file2.txt file3.txt $> cat file1.txt line 1 line 2 line 3 line 4 NEW STRING line 6 $> cat file2.txt line 1 line 2 line 3 line 4 NEW STRING line 6
列表理解也可以实现同样的目的。 下面是同一个脚本的一行代码:
cat /etc/passwd | python -c 'import sys; print "\n".join(["CUSTOM" if index == 5 else line.strip() for index,line in enumerate(sys.stdin,1)])'
或没有cat
python -c 'import sys; print "\n".join(["CUSTOM" if index == 5 else line.strip() for index,line in enumerate(sys.stdin,1)])' < /etc/passwd
剩下的就是简单地将编辑内容的输出重定向到另一个带有> output.txt
文件
您可以在Ex模式下使用Vim:
for b in 1 2 3 4 do ex -sc '5c|Good Morning' -cx file"$b".txt done
-
5
选择第5行 -
c
替换文字 -
x
写入是否已经进行了更改(他们有)并退出
以下是一个bash脚本,它包含了本答案中建议的perl进程
例:
的/ tmp /它
console: enabled:false
然后运行以下命令:
$ search_and_replace_on_line_of_file.sh false true 2 /tmp/it
并且文件现在包含
的/ tmp /它
console: enabled:true
search_and_replace_on_line_of_file.sh
function show_help() { IT=$(CAT < replaces false with true on line 52 of file /tmp/it ) echo "$IT" exit } if [ "$1" == "help" ] then show_help fi if [ -z "$4" ] then show_help fi SEARCH_FOR=$1 REPLACE_WITH=$2 LINE_NO=$3 FILE_NAME=$4 perl -i -pe "s/$SEARCH_FOR/$REPLACE_WITH/ if $.==$LINE_NO" $FILE_NAME