如何替换多个文本文件的第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

  1. 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

  2. SED

     sed -i '5s/.*/ Good Morning /' file{1..4}.txt 

    说明:

    • -i :与perl一样,编辑文件到位。

    默认情况下, sed打印输入文件的每一行。 5s/pattern/replacement/表示在第5行替换替换模式。

  3. 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 。 在awkNR是当前行号, $0是当前行的内容。 因此,该脚本将仅在第5行用“早安”替换该行( $0 )。 1; 是“打印线”的awk

    ¹ 较新的版本就像devnull在他的回答中所表现的那样。

  4. 的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 
  1. 5选择第5行

  2. c替换文字

  3. 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