让M=3
和N=4
.我想用 line M
in替换file1
line N
in file2
。我可以使用以下命令替换字符串sed
:
sed -i '3s/.*/stringToReplace/' file1
我可以用它来awk
获取线路N
file2
awk 'NR==4' "file2"
我怎样才能将这两者结合起来?如果我尝试
sed -i '3s/.*/{awk 'NR==4' "file2"}/' file1
然后我M
用字面意思替换 line {awk 'NR==4' "file2"}
。
答案1
有多种方法可以正确执行此操作以处理任意输入。
使用 GNUsed
和支持以下功能的系统/dev/stdin
:
sed -n "${n}{p;q;}" file2 | sed -e "$m{r/dev/stdin" -e 'd;p;}' file1
或者,稍微短一点 1:
sed $n'!d;q' file2 | sed -e $m'{r /dev/stdin' -e 'd;p;}' file1
使用任何sed
支持进程替换的 shell
sed '1h;1d;'$((m+1))'x' <(sed ${n}'!d;q' file2) file1
也可以写成
sed ${n}'!d;q' file2 | sed '1h;1d;'$((m+1))'x' - file1
基本上,一个sed
调用从中提取行,n
然后file2
由另一个调用sed
作为第一个操作数读取:它将其保存到保持缓冲区中,删除它,然后读取第二个操作数的内容,即file1
,在线时交换缓冲区m+1
(组合输入) )。
任何支持通过以下sed
方式读取脚本文件的人都可以运行:-f
stdin
sed ${n}'!d;i\
'${m}'c\\
s/\\/&&/g
q' file2 | sed -f - file1
在这里,第一个sed
将行n
变成file2
脚本文件,例如
${m}c\
line_n_content_here_with_any_backslash_escaped
然后由第二个用来sed
处理file1
(即将行替换m
为以下文本...)。原始文本中存在的任何反斜杠(以及任何嵌入的换行符 - 但这里只有一行)都必须被转义,因为当使用任何a\
,i\
或c\
添加文本时
<backslash> characters in text shall be removed, and the following character shall be treated literally.
对于任何sed
,您都可以使用一直流行的s
ubstitute 命令确保插入sed
替换的字符串转义所有保留字符- 在这种特殊情况下,它只是一行,例如
line=$(sed ${m}'!d;s|[\/&]|\\&|g;q' file2)
然后替换:
sed ${m}'s/.*/'"$line"'/' file1
对于巨大的输入文件,您可以运行:
{ head -n $((m-1)); { head -n $((n-1)) >/dev/null; head -n 1; } <file2; head -n 1 >/dev/null; cat; } <file1
它做了这样的事情:
print (m-1) lines from file1
discard (n-1) lines from file2
print n-th line from file2
discard m-th line from file1
print the remaining lines from file1
虽然有些head
人很蠢而且不会符合标准所以这并不适用于所有设置......但在它适用的情况下,它在速度方面胜过sed
等。awk
1:对于某些 shell,您可能需要禁用历史扩展才能!
工作...
另外,$n
并且$m
实际上不需要在这里引用,因为它们应该是正整数,尽管它也没有什么坏处
答案2
尝试这个:
$ cat f1
foo
bar
xyz
baz
temp
good
$ cat f2
1
2
3
4
5
6
$ awk -v m=3 -v n=4 'NR==FNR{if(FNR==n) s=$0; next} FNR==m{$0=s} 1' f2 f1
foo
bar
4
baz
temp
good
NR==FNR
仅当第一个文件正在处理时才为真if(FNR==n) s=$0
如果是第n行,则保存到变量next
这样只要处理第一个文件就不会执行其余代码FNR==m{$0=s}
如果是第二个文件参数的第 m 行,则替换它1
打印输入记录,包括任何修改- 注意文件输入参数的顺序
可以用来if(FNR==n){s=$0;nextfile}
避免处理第 n 行之后的行
从GNU awk 手册- 谢谢@iruvar
注意:多年来,nextfile 是一个常见的扩展名。 2012 年 9 月,它被纳入 POSIX 标准。请参阅奥斯汀集团网站。
答案3
短的sed方法:
样本文件f1
:
f1 line1
f1 line2
f1 line3
f1 line4
f1 line5
样本文件f2
:
ID1,value12,value13
ID1,value22,value23
ID1,value32,value33
ID2,/value42/,~value43~
ID3,value52,value53
工作:
sed '3 s/.*/'"$(sed -n '4{ s/\//\\\//g;p;}' f2)"'/;' f1
输出:
f1 line1
f1 line2
ID2,/value42/,~value43~
f1 line4
f1 line5
答案4
不要将 awk 与 sed 混合使用。您可以使用完整的 awk 解决方案
文件1:
file1 1
file1 2
file1 3
file1 4
文件2:
file2 1
file2 2
file2 3
file2 4
awk -v m=3 -v n=4 'NR == FNR { filea[FNR]=$0 } FNR != NR { fileb[FNR]=$0 } END { for (i=1;i<=FNR;i++) { if ( i == m ) { print fileb[n] } else { print filea[i] } } } ' file1 file2
细分:
NR == FNR {
filea[FNR]=$0
}
FNR != NR {
fileb[FNR]=$0
}
END {
for (i=1;i<=FNR;i++) {
if ( i == m ) {
print fileb[n]
}
else {
print filea[i]
}
}
}
我们比较 NR 和 FNR 来确定 file1 和 file2 中的记录(当 NR=FNR 时,我们知道我们在第一个文件中)。我们用 file1 中的记录设置数组 filea,用 file2 中的记录设置 fileb。然后,我们循环遍历数组 filea 中的所有记录,仅当传递的参数 m 不等于 3 时才打印内容。如果是,则打印由传递的参数 n 确定的数组 fileb 的下标