bash 如何按行号替换文本文件中的整行

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11145270/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 22:18:03  来源:igfitidea点击:

How to replace an entire line in a text file by line number

bashtextreplacesed

提问by user788171

I have a situation where I want a bash script to replace an entire line in a file. The line number is always the same, so that can be a hard-coded variable.

我有一种情况,我想要一个 bash 脚本来替换文件中的整行。行号始终相同,因此可以是硬编码变量。

I'm not trying to replace some sub-string in that line, I just want to replace that line entirely with a new line.

我不想替换该行中的某些子字符串,我只想用新行完全替换该行。

Are there any bash methods for doing this (or something simple that can be thrown into a .sh script).

是否有任何 bash 方法可以执行此操作(或一些可以放入 .sh 脚本的简单方法)。

回答by chepner

Not the greatest, but this should work:

不是最好的,但这应该有效:

sed -i 'Ns/.*/replacement-line/' file.txt

where Nshould be replaced by your target line number. This replaces the line in the original file. To save the changed text in a different file, drop the -ioption:

whereN应该替换为您的目标行号。这将替换原始文件中的行。要将更改的文本保存在不同的文件中,请删除-i选项:

sed 'Ns/.*/replacement-line/' file.txt > new_file.txt

回答by Kyle

I actually used this script to replace a line of code in the cron file on our company's UNIX servers awhile back. We executed it as normal shell script and had no problems:

不久前,我实际上使用此脚本替换了我们公司 UNIX 服务器上的 cron 文件中的一行代码。我们像普通的 shell 脚本一样执行它,没有任何问题:

#Create temporary file with new line in place
cat /dir/file | sed -e "s/the_original_line/the_new_line/" > /dir/temp_file
#Copy the new file over the original file
mv /dir/temp_file /dir/file

This doesn't go by line number, but you can easily switch to a line number based system by putting the line number before the s/and placing a wildcard in place of the_original_line.

这不是按行号进行的,但是您可以通过将行号放在 之前s/并在the_original_line.

回答by steveha

Let's suppose you want to replace line 4 with the text "different". You can use AWK like so:

假设您想用文本“不同”替换第 4 行。您可以像这样使用 AWK:

awk '{ if (NR == 4) print "different"; else print 
awk 'NR==4 {
awk 'NR==4 {
Lorem ipsum dolor sit amet,
consectetur adipiscing elit. 
Duis eu diam non tortor laoreet 
bibendum vitae et tellus.
="different"} 1' input_file.txt
="different"} { print }' input_file.txt
}' input_file.txt > output_file.txt

AWK considers the input to be "records" divided into "fields". By default, one line is one record. NRis the number of records seen. $0represents the current complete record (while $1is the first field from the record and so on; by default the fields are words from the line).

AWK 将输入视为分为“字段”的“记录”。默认情况下,一行为一条记录。 NR是看到的记录数。 $0表示当前的完整记录($1而是记录中的第一个字段,依此类推;默认情况下,字段是行中的单词)。

So, if the current line number is 4, print the string "different" but otherwise print the line unchanged.

因此,如果当前行号为 4,则打印字符串“不同”,否则打印未更改的行。

In AWK, program code enclosed in { }runs once on each input record.

在 AWK 中,包含在{ }每个输入记录中的程序代码运行一次。

You need to quote the AWK program in single-quotes to keep the shell from trying to interpret things like the $0.

您需要用单引号引用 AWK 程序,以防止 shell 尝试解释$0.

EDIT: A shorter and more elegant AWK program from @chepner in the comments below:

编辑:@chepner 在下面的评论中提供了一个更短、更优雅的 AWK 程序:

$ sed '1 c\
> newline text' test.txt

Only for record (i.e. line) number 4, replace the whole record with the string "different". Then for every input record, print the record.

仅对于记录(即行)编号 4,将整个记录替换为字符串“不同”。然后对于每个输入记录,打印记录。

Clearly my AWK skills are rusty! Thank you, @chepner.

显然我的 AWK 技能已经生锈了!谢谢你,@chepner。

EDIT: and see also an even shorter version from @Dennis Williamson:

编辑:还有来自@Dennis Williamson 的更短的版本:

newline text
consectetur adipiscing elit. 
Duis eu diam non tortor laoreet 
bibendum vitae et tellus.

How this works is explained in the comments: the 1always evaluates true, so the associated code block always runs. But there is no associated code block, which means AWK does its default action of just printing the whole line. AWK is designed to allow terse programs like this.

注释中解释了这是如何工作的:1始终评估为真,因此关联的代码块始终运行。但是没有关联的代码块,这意味着 AWK 执行它的默认操作,即打印整行。AWK 旨在允许像这样的简洁程序。

回答by Eric Robinson

Given this test file (test.txt)

鉴于此测试文件(test.txt)

i=1
while read line;do
  if((i==N));then
    echo 'xxx'
  elif((i==M));then
    echo 'yyy'
  else
    echo "$line"
  fi
  ((i++))
done  < orig-file > new-file

the following command will replace the first line to "newline text"

以下命令将第一行替换为“换行文本”

IFS= read -r line

Result:

结果:

perl -ne 'if($.==N){print"xxx\n"}elsif($.==M){print"yyy\n"}else{print}' < orig-file > new-file

more information can be found here

更多信息可以在这里找到

http://www.thegeekstuff.com/2009/11/unix-sed-tutorial-append-insert-replace-and-count-file-lines/

http://www.thegeekstuff.com/2009/11/unix-sed-tutorial-append-insert-replace-and-count-file-lines/

回答by Nahuel Fouilleul

in bash, replace N,M by the line numbers and xxx yyy by what you want

在 bash 中,用行号替换 N,M,用你想要的替换 xxx yyy

# Replace the line of the given line number with the given replacement in the given file.
function replace-line-in-file() {
    local file=""
    local line_num=""
    local replacement=""

    # Escape backslash, forward slash and ampersand for use as a sed replacement.
    replacement_escaped=$( echo "$replacement" | sed -e 's/[\/&]/\&/g' )

    sed -i "${line_num}s/.*/$replacement_escaped/" "$file"
}

EDIT

编辑

In fact in this solution there are some problems, with characters "\0" "\t" and "\"

实际上在这个解决方案中存在一些问题,字符“\0”“\t”和“\”

"\t", can be solve by putting IFS= before read: "\", at end of line with -r

"\t", 可以通过将 IFS= 放在 read 之前解决:"\", 在行尾加上 -r

 # To update/replace the new line string value with the exiting line of the file
 MyFile=/tmp/ps_checkdb.flag

 `sed -i "${index}s/.*/${newLine}/" $MyFile`

but for "\0", the variable is truncated, there is no a solution in pure bash : Assign string containing null-character (\0) to a variable in BashBut in normal text file there is no nul character \0

但是对于“\0”,变量被截断,纯bash中没有解决方案: 将包含空字符(\0)的字符串分配给Bash中的变量但是在普通文本文件中没有空字符\0

perl would be a better choice

perl 会是更好的选择

LineString=`sed "$index!d" $MyFile` 

回答by Daniel Bigham

sed -i '' -e 's/text-on-line-to-be-changed.*/text-to-replace-the=whole-line/' file-name

回答by Kanagavelu Sugumar

Excellent answer from Chepner. It is working for me in bash Shell.

Chepner的出色回答。它在 bash Shell 中对我来说有效。

#!/bin/bash
echo "-> start"
for i in $(seq 5); do
  # passing parameters to sed
  j=$(($i+3))
  sed -i "${j}s/.*/replaced by '$i'!/" output.dat
done
echo "-> finished"
exit 

here
index- Line no
newLine- new line string which we want to replace.


Similarly below code is used to read a particular line in the file. This won't affect the actual file.

这里
index- 行号
newLine- 我们要替换的新行字符串。


类似地,下面的代码用于读取文件中的特定行。这不会影响实际文件。

a
b
c
d
e
f
g
h
i
j

here
!d- will delete the lines other than line no $indexSo we will get the output as line string of no $indexin the file.

这里
!d- 将删除除行号以外的行$index所以我们将$index在文件中将输出作为行号字符串。

回答by nakeer

On mac I used

在 mac 上我用过

a
b
c
replaced by '1'!
replaced by '2'!
replaced by '3'!
replaced by '4'!
replaced by '5'!
i
j

回答by AndreH

You can even pass parameters to the sed command:

您甚至可以将参数传递给 sed 命令:

test.sh

测试文件

##代码##

orignial output.dat:

原始输出.dat:

##代码##

Executing ./test.shgives the new output.dat

执行./test.sh给出新的 output.dat

##代码##