我想替换多个文本文件的第 5 行(文件1.txt,文件2.txt,文件3.txt,文件4.txt) 使用单个终端命令输入字符串“ Good Morning ”。
所有文本文件都位于我的 上~/Desktop
。
注意:我的桌面由 6 个 .txt 文件组成。我只想将更改应用于上面提到的 4 个文本文件。
答案1
以下是一些方法。我正在使用括号扩展(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
后面跟有文件扩展名后缀,则将为每个被修改的文件创建备份。例如:如果在执行过程中被修改,则-i.bak
创建一个。file1.txt.bak
file1.txt
-p
:表示逐行读取输入文件,应用脚本并打印。-e
:允许您从命令行传递脚本。s/.*/ Good Morning /
:此操作将用“早上好”替换当前行 ( ) 中的文本.*
。$.
是一个特殊的 Perl 变量,用于保存输入文件的当前行号。因此,s/foo/bar/ if $.==5
表示仅在第 5 行foo
用替换。bar
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
),然后将其重命名以覆盖原始文件。 bash 循环for f in file{1..4}.txt; do ... ; done
只是遍历每个file{1..4}.txt
,将当前文件名保存为$f
。 在 中awk
,NR
是当前行号,$0
是当前行的内容。 因此,脚本将$0
仅在第 5 行用“早上好”替换行()。1;
表示awk
“打印行”。¹新版本确实如 devnull 在其回答。
核心工具
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 行,然后是“早上好”,然后是其余的行)并将它们重定向到文件。
答案2
您可以使用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 行
答案3
我没有看到 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,我们将写出不同的行。剩下的只是用临时文件替换旧文件演示:
$> 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
答案4
以下是一个总结的 bash 脚本本答案中建议的 perl 流程
例子:
/tmp/它
console:
enabled:false
然后运行以下命令:
$ search_and_replace_on_line_of_file.sh false true 2 /tmp/it
现在文件包含
/tmp/它
console:
enabled:true
在线搜索和替换文件.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