Shell 搜索一个字符串并替换搜索字符串上方的另一个字符串

Shell 搜索一个字符串并替换搜索字符串上方的另一个字符串,shell,awk,sed,Shell,Awk,Sed,我有一个下面几行的文件 123 456 123 789 abc efg xyz 我需要用abc搜索,并用111替换前面的123。这是要求,abc在文件中仅出现一次,但123可以多次出现,并且123可以位于abc上方的任何位置。 请帮帮我 我试过用下面的命令 sed -i.bak "/abc/!{x;1!p;d;};x;s/123/1111" filename 使用上面的命令,它只替换123,如果123刚好在abc上方,如果123在abc上方两行,则替换失败。要做的不止这些。这里有一个: se

我有一个下面几行的文件

123
456
123
789
abc
efg
xyz
我需要用
abc
搜索,并用
111
替换前面的
123
。这是要求,
abc
在文件中仅出现一次,但
123
可以多次出现,并且123可以位于
abc
上方的任何位置。 请帮帮我

我试过用下面的命令

sed -i.bak "/abc/!{x;1!p;d;};x;s/123/1111" filename

使用上面的命令,它只替换
123
,如果
123
刚好在
abc
上方,如果
123
abc
上方两行,则替换失败。

要做的不止这些。这里有一个:

sed -i.bak '1{h;d;};/123/{x;p;d;};/abc/{x;s/123/111/;p;d;};H;${x;p;};d' filename

要做到这一点,还有很多事情要做。这里有一个:

sed -i.bak '1{h;d;};/123/{x;p;d;};/abc/{x;s/123/111/;p;d;};H;${x;p;};d' filename

ed
对于复杂的脚本文件编辑非常方便:

ed -s file <<EOF
/^abc$/;?^123$?;.c
111
.
w
EOF

ed-s文件
ed
对于复杂的脚本文件编辑非常方便:

ed -s file <<EOF
/^abc$/;?^123$?;.c
111
.
w
EOF
ed-s文件这可能适合您(GNU-sed):

这会将文件读入内存,并在
abc
之前最后出现的
123
前面插入
111

内存占用较少的解决方案:

sed -E '/^123$/{:a;N;/\n123$/{h;s///p;g;s/.*\n//;ba};/\nabc$/!ba;s/^/111\n/}' file
这将在包含
123
的行之后收集行。如果遇到另一条包含
123
的线路,它会卸载之前的所有线路,并再次开始收集线路。如果它发现一行包含
abc
,它将在迄今为止收集的行的前面插入
111

另一种选择:

sed '/abc/{x;/./{s/^/111\n/p;z};x;b};/123/{x;/./p;x;h;$!d;b};x;/./{x;H;$!d};x' file 
这可能适用于您(GNU-sed):

这会将文件读入内存,并在
abc
之前最后出现的
123
前面插入
111

内存占用较少的解决方案:

sed -E '/^123$/{:a;N;/\n123$/{h;s///p;g;s/.*\n//;ba};/\nabc$/!ba;s/^/111\n/}' file
这将在包含
123
的行之后收集行。如果遇到另一条包含
123
的线路,它会卸载之前的所有线路,并再次开始收集线路。如果它发现一行包含
abc
,它将在迄今为止收集的行的前面插入
111

另一种选择:

sed '/abc/{x;/./{s/^/111\n/p;z};x;b};/123/{x;/./p;x;h;$!d;b};x;/./{x;H;$!d};x' file 

这是一个典型的情况,您可以跟踪上一行并根据满足当前行的条件更改内容。通常,awk程序如下所示:

awk '(FNR==1){prev=$0; next}
     (condition_on_$0) { action_on_prev }
     { print prev; prev = $0 }
     END { print $0 }'
因此,在OP的情况下,这将是:

awk '(FNR==1){prev=$0; next}
     $0 == "abc" { if (prev == "123") prev = "111" }
     { print prev; prev = $0 }
     END { print $0 }'

这是一个典型的情况,您可以跟踪上一行并根据满足当前行的条件更改内容。通常,awk程序如下所示:

awk '(FNR==1){prev=$0; next}
     (condition_on_$0) { action_on_prev }
     { print prev; prev = $0 }
     END { print $0 }'
因此,在OP的情况下,这将是:

awk '(FNR==1){prev=$0; next}
     $0 == "abc" { if (prev == "123") prev = "111" }
     { print prev; prev = $0 }
     END { print $0 }'

感谢您的帮助,这是可行的,但是当我使用变量作为“abc”时,变量替换失败了
var=abc sed-I.bak'1{h;d;}/123/{x;p;d;}/${var}/{x;s/123/111/;p;d;};H${x;p;};d'filename@kiranpaila:请尝试使用
sed“…$var…”
(注意双引号和缺少括号)。如何使用下面的命令仅搜索替换sed-i.bak'1{h;d;}的以上5行/123/{x;p;d;}/abc/{x;s/123/111/;p;d;};H${x;p;};d'filename只需要检查前面几行来替换,而不是检查前面所有的行谢谢帮助,这是可行的,但是当我使用变量来“abc”时,变量替换失败了
var=abc sed-I.bak'1{h;d;}/123/{x;p;d;}/${var}/{x;s/123/111/;p;d;};H${x;p;};d'filename@kiranpaila:请尝试使用
sed“…$var…”
(注意双引号和缺少括号)。如何使用下面的命令仅搜索替换sed-i.bak'1{h;d;}的以上5行/123/{x;p;d;}/abc/{x;s/123/111/;p;d;};H${x;p;};d’filename只需检查前几行即可替换,而不必检查前几行