如何替换多个文本文件第5行上的字符串?


22

我想使用单个终端命令用字符串“ Good Morning” 替换多个文本文件(file1.txt,file2.txt,file3.txt,file4.txt)的第五行。

所有的文本文件都位于我的~/Desktop

注意:我的桌面包含6个.txt文件。我只想将更改应用于上述4个文本文件。

Answers:


40

这里有一些方法。我正在使用括号扩展file{1..4}.txt),这意味着file1.txt file2.txt file3.txt file4.txt

  1. 佩尔

    perl -i -pe 's/.*/ Good Morning / if $.==5' file{1..4}.txt

    说明:

    • -i:导致perl就地编辑文件,更改原始文件。

      如果-i后跟文件扩展名后缀,则将为每个被修改的文件创建一个备份。例如:-i.bak创建一个在执行过程中被修改的file1.txt.bakif file1.txt

    • -p:表示逐行读取输入文件,应用脚本并打印。

    • -e:允许您从命令行传递脚本。

    • s/.*/ Good Morning /:将会用.*早安替换当前行()中的文本。

    • $.是一个特殊的Perl变量,用于保存输入文件的当前行号。因此,,s/foo/bar/ if $.==5意味着仅在第5行替换foobar

  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),然后将其重命名以覆盖原始文件。bash循环for f in file{1..4}.txt; do ... ; done只是遍历每个循环file{1..4}.txt,将当前文件名另存为$f。在中awkNR是当前行号,是当前行$0的内容。因此,脚本$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:打印前四行

    • echo " Good Morning ":打印“早安”

    • tail -n +6:打印从第六行到文件末尾的所有内容

    使用( )这三个命令的括号可以捕获所有三个命令的输出(因此,第1行,第4行,然后是“早安”,然后是其余各行),并将它们重定向到文件。


23

您可以使用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行。


2

我没有看到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


1

您可以在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 写(如果有)更改并退出


0

以下是一个bash脚本,它包装了此答案中建议的perl进程

例:

/ tmp / it

console:
  enabled:false

然后运行以下命令:

$ search_and_replace_on_line_of_file.sh false true 2 /tmp/it

现在文件包含

/ tmp / it

console:
  enabled:true

search_and_replace_on_line_of_file.sh

function show_help()
{
  IT=$(CAT <<EOF

  usage: SEARCH REPLACE LINE_NUM FILE

  e.g. 

  false true 52 /tmp/it  -> 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 
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.