【发布时间】:2012-06-24 02:34:45
【问题描述】:
我有一种情况,我想要一个 bash 脚本来替换文件中的整行。 行号始终相同,因此可以是硬编码变量。
我不想替换该行中的某些子字符串,我只想用新行完全替换该行。
是否有任何 bash 方法可以做到这一点(或者可以放入 .sh 脚本的简单方法)。
【问题讨论】:
我有一种情况,我想要一个 bash 脚本来替换文件中的整行。 行号始终相同,因此可以是硬编码变量。
我不想替换该行中的某些子字符串,我只想用新行完全替换该行。
是否有任何 bash 方法可以做到这一点(或者可以放入 .sh 脚本的简单方法)。
【问题讨论】:
如果您想为 lineNumber 和 replacementLine 使用参数,那么 awk 就不能轻松工作(对我来说)。我跑了 1 小时试试你可以在下面看到:)
lineNumber=$(grep --line-number "u want to replace line any keyword" values.txt | cut -f1 -d:)
replacedLine="replacing new Line "
# for sed prepare => if your replacedLine have '/' character (URL or something) u must use command bellow.
replacedLine=${replacedLine//\//\\\/}
sed -i $lineNumber's/.*/'"$replacedLine"'/' values.txt
【讨论】:
grep 这里不需要。
sed c\
sed c\ 实际上不会更改文件,因此您需要将其输出发送到临时文件,然后将 cat 临时文件发送到原始文件。匹配模式不是必需的,因为我们可以指定行。示例:sed '1 c\' => 将替换第 1 行中的文本。
在编写命令时,c\ 部分之后的任何内容都将换行并应包含新行文本。
最后,用文本“foo”“替换”名为original_file.txt 的文件中的第 1 行的示例。请注意,我们正在获取 sed 输出并保存在临时文件中,然后将临时文件输出回原始文件:
# file contents
$ cat original_file.txt
bar
# the replace command
$ sed '1 c\
foo' original_file.txt > temp_file.txt
# output contents of temp_file and overwrite original
$ cat temp_file.txt > original_file.txt
# delete the temp file
$ rm -rf temp_file.txt
【讨论】:
在我使用的 mac 上
sed -i '' -e 's/text-on-line-to-be-changed.*/text-to-replace-the=whole-line/' file-name
【讨论】:
-i '':BSD sed: extra characters at the end of d command - Stack Overflow
# Replace the line of the given line number with the given replacement in the given file.
function replace-line-in-file() {
local file="$1"
local line_num="$2"
local replacement="$3"
# 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"
}
【讨论】:
您甚至可以将参数传递给 sed 命令:
test.sh
#!/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
原始输出.dat:
a
b
c
d
e
f
g
h
i
j
执行 ./test.sh 给出新的 output.dat
a
b
c
replaced by '1'!
replaced by '2'!
replaced by '3'!
replaced by '4'!
replaced by '5'!
i
j
【讨论】:
line=5; sed -i "${line}s/.*/replaced by '$i'!/" output.dat
Chepner 的出色回答。 它在 bash Shell 中为我工作。
# 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`
这里 index - 行号 newLine - 我们要替换的新行字符串。
同样,下面的代码用于读取文件中的特定行。这不会影响实际文件。
LineString=`sed "$index!d" $MyFile`
这里 !d - 将删除除$index 之外的行
所以我们会得到文件中没有$index的行字符串的输出。
【讨论】:
${newline}?
在 bash 中,用行号替换 N,M,用你想要的替换 xxx yyy
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
编辑
实际上在这个解决方案中存在一些问题,字符“\0”、“\t”和“\”
"\t",可以通过在读取前加上 IFS= 来解决: "\",在行尾加上 -r
IFS= read -r line
但是对于“\0”,变量被截断,纯 bash 没有解决方案: Assign string containing null-character (\0) to a variable in Bash 但在普通文本文件中没有空字符 \0
perl 会是更好的选择
perl -ne 'if($.==N){print"xxx\n"}elsif($.==M){print"yyy\n"}else{print}' < orig-file > new-file
【讨论】:
/、-、= 和;,我也不需要转义任何字符。谢谢!附言。发表此评论后,我向下滚动 Daniel Bigham 的回答。
假设您想用文本“不同”替换第 4 行。您可以像这样使用 AWK:
awk '{ if (NR == 4) print "different"; else print $0}' input_file.txt > output_file.txt
AWK 将输入视为分为“字段”的“记录”。默认情况下,一行是一条记录。 NR 是看到的记录数。 $0 代表当前完整的记录($1 是记录中的第一个字段,依此类推;默认情况下,字段是该行中的单词)。
因此,如果当前行号为 4,则打印字符串“不同”,否则打印该行不变。
在 AWK 中,包含在 { } 中的程序代码在每个输入记录上运行一次。
您需要在单引号中引用 AWK 程序,以防止 shell 尝试解释 $0 之类的内容。
编辑:@chepner 在下面的 cmets 中提供了一个更短、更优雅的 AWK 程序:
awk 'NR==4 {$0="different"} { print }' input_file.txt
仅对于第 4 条记录(即行),将整个记录替换为字符串“不同”。然后对于每条输入记录,打印记录。
显然我的 AWK 技能已经生疏了!谢谢你,@chepner。
编辑:另请参阅@Dennis Williamson 的更短版本:
awk 'NR==4 {$0="different"} 1' input_file.txt
cmets 中解释了其工作原理:1 始终评估为 true,因此相关代码块始终运行。但是没有关联的代码块,这意味着 AWK 执行其仅打印整行的默认操作。 AWK 旨在允许这样的简洁程序。
【讨论】:
awk 'NR==4 {$0="different"} { print }' input_file.txt.
awk 'NR==4 {$0="different"}1' input_file.txt
1 有什么作用? (注意:我测试过它确实有效!我只是不明白如何。)
给定这个测试文件(test.txt)
Lorem ipsum dolor sit amet,
consectetur adipiscing elit.
Duis eu diam non tortor laoreet
bibendum vitae et tellus.
以下命令会将第一行替换为“换行符”
$ sed '1 c\
> newline text' test.txt
结果:
newline text
consectetur adipiscing elit.
Duis eu diam non tortor laoreet
bibendum vitae et tellus.
更多信息可以在这里找到
http://www.thegeekstuff.com/2009/11/unix-sed-tutorial-append-insert-replace-and-count-file-lines/
【讨论】:
sed '1 cnewline text' test.txt 也会这样做。
不是最好的,但这应该可以:
sed -i 'Ns/.*/replacement-line/' file.txt
N 应替换为您的目标行号。这将替换原始文件中的行。要将更改的文本保存在不同的文件中,请删除 -i 选项:
sed 'Ns/.*/replacement-line/' file.txt > new_file.txt
【讨论】:
sed: -e expression #1, char 26: unknown option to ``s' 而我的线路是:sed -i '7s/.*/<param-value>http://localhost:8080/ASDF/services/REWS.REWSHttpSoap12Endpoint/</param-value>/' $TCE_SVN_HOME\trunk\tce\EWC\WebContent\WEB-INF\web.xml。有什么想法吗?
/ 将被解释为s 命令的结束斜线,除非转义(\/)。不过,最简单的做法是选择一个不同的、未使用的字符作为分隔符。例如,sed -i '7s{.*}{<param-value>http://...}' $TCE_SVN_HOME/trunk....
s 后面的第一个字符决定了分隔符。因此,要更改您的命令以使用例如#,它将是这样的:sed -i '7s#.*#<param-value>http://localhost:8080/ASDF/services/REWS.REWSHttpSoap12Endpoint/</param-value>#'
-e,如果-i 也给出;因此,正确的命令变为:sed -e 'Ns/.*/replacement-line/' -i '' file.txt
sed -i "Ns/.*/foo=$myVar" file.txt.
不久前,我实际上使用此脚本替换了我们公司 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
这不是按行号进行的,但是您可以通过将行号放在s/ 之前并用通配符代替the_original_line 来轻松切换到基于行号的系统。
【讨论】:
sed -e "s/.../.../" /dir/file > /dir/temp_file
sed -e "s/.../.../" /dir/file > /dir/file