我需要交换这些行,仅当匹配的字符串都在两行中时:
前:
REF*CE*-------------------------
REF*1W*-------------------------
后:
REF*1W*-------------------------
REF*CE*-------------------------
我尝试了这个,它不起作用:
ed -s testfile.txt <<<$'/REF*CE*/-0,/REF*CE*/+0m/REF*1W*/\nw\nq'
答案1
sed -e :a -e '$!N;s/^\(REF\*CE.*\)\n\(REF\*1W.*\)/\2\n\1/;ta' -e 'P;D' <testfile.txt
- 如果我们不在最后一行,则附加下一行。
- 仅当匹配时才会在当前行上进行替换
substring containing pattern 1 + newline + substring containing pattern 2
。替换会翻转两个子字符串。替换后返回标签:a。 - 如果没有匹配则按原样打印模式空间。然后删除模式空间并再次开始循环。
带有一些周围线条的示例...
In:
XEF*CE*-------------------------
REF*CE*-------------------------
REF*1W*-------------------------
REF*2W*-------------------------
Out:
XEF*CE*-------------------------
REF*1W*-------------------------
REF*CE*-------------------------
REF*2W*-------------------------
更一般地适用于任何模式 1 和模式 2
sed -e :a \
-e "\$!N; s/^\(.*${pattern1}.*\)\n\(.*${pattern2}.*\)/\2\n\1/;ta" \
-e 'P;D' < inputfile
答案2
如何交换与特定正则表达式匹配的两行(可能相距很远)的通用解决方案ed
:
- 复制一行到第二行之后。
- 移动第二行位于原始第一行之后。
- 删除第一个原始行。
或者,使用ed
编辑命令:
/pat1/t/pat2/
?pat2?m/pat1/
?pat1?d
示例为文件
CLP*815900102*2*489.8*101.5*82.29*13*PVJLS03YP0000*13*7
AMT*AU*489.8
REF*6R*00000000002
DTM*472*20160528
CAS*OA*23*306.01
CAS*PR*2*82.29
SVC*HC:99212:25*489.8*101.5**1
AMT*B6*411.43
我们想将第一AMT
行与第二CAS
行交换。 pat1
将会是^AMT\*AU
并且pat2
将会是^CAS\*PR
。请注意,我们需要对其进行转义,*
以便在正则表达式中按字面意思进行处理。
我在下面注释了更改,以便更容易看到它们。指示XXX
每次操作后文件中的当前位置。
/^AMT\*AU/t/^CAS\*PR/
产生CLP*815900102*2*489.8*101.5*82.29*13*PVJLS03YP0000*13*7 AMT*AU*489.8 <-- Line copied *from* here REF*6R*00000000002 DTM*472*20160528 CAS*OA*23*306.01 CAS*PR*2*82.29 AMT*AU*489.8 <-- Line copied *to* here (XXX) SVC*HC:99212:25*489.8*101.5**1 AMT*B6*411.43
?^CAS\*PR?m/^AMT\*AU/
产生CLP*815900102*2*489.8*101.5*82.29*13*PVJLS03YP0000*13*7 AMT*AU*489.8 CAS*PR*2*82.29 <-- line moved here (XXX) REF*6R*00000000002 DTM*472*20160528 CAS*OA*23*306.01 AMT*AU*489.8 <-- line previous to this deleted SVC*HC:99212:25*489.8*101.5**1 AMT*B6*411.43
?^AMT\*AU?d
产生CLP*815900102*2*489.8*101.5*82.29*13*PVJLS03YP0000*13*7 CAS*PR*2*82.29 <-- the line before this was removed (XXX) REF*6R*00000000002 DTM*472*20160528 CAS*OA*23*306.01 AMT*AU*489.8 SVC*HC:99212:25*489.8*101.5**1 AMT*B6*411.43
作为一个容易记住的“一句话”:
pat1='^AMT\*AU'; pat2='^CAS\*PR'; printf '/%s/t/%s/\n?%s?m/%s/\n?%s?d\nwq\n' "$pat1" "$pat2" "$pat2" "$pat1" "$pat1" | ed -s file
请注意,通过第二次运行完全相同的操作,这是可逆的,即第一个或第二个模式并不重要。
答案3
我们可以通过将匹配的行放入保持缓冲区,读取下一行并打印它,然后将保持缓冲区与模式缓冲区交换并再次打印来获得所需的效果。
bash-4.3$ sed -n '/^REF\*CE/!p;/^REF\*CE/{h;n;p;x;p}' input.txt
some line here
REF*BB*106497026---------------
REF*1W*723266637---------------
REF*CE*NEW JERSEY--------------
SVC*HC^S5102*78.5*78.5**1------
another line there
答案4
我有这样的简单解决方案:假设您想将文件中包含“XXXX”的行与包含“YYYY”的行交换,则只提供一行包含“XXXX”并且只有一行包含“YYYY”
示例文件如下: ssss dddd
aaaa ffff
ddd rrrr
ddddd XXXX
ddddde
ffff
ffff
fff
eeee YYYY
ghghgh
hhhhh
我的“sed”命令是 sed 's/XXXX/ZZZZ/g;s/YYYY/XXXX/g;s/ZZZZ/YYYY/g' 请记住“ZZZZ”字符串不应出现在文件中。