搜索特定模式并使用新模式替换其上方的任何单词或行

时间:2017-07-24 15:13:45

标签: vim awk sed

假设我有以下句子:

jack and jill
climbs up a hill

我想在文件中搜索hill并将jill替换为jerry,即hill上方的行,{{1}}保持原样。是否可以使用vim编辑器或awk / sed?

7 个答案:

答案 0 :(得分:5)

使用GNU sed:

sed 'N;/\n.*hill/s/jill\(.*[^\n]\)/jerry\1/' file
  • N:将下一行添加到模式空间
  • /\n.*hill/:如果在新行之后找到hill
  • s/jill\(.*[^\n]\)/:替换在新线之前找到的jill以及跟随捕获的字符
  • jerry\1jerry字符串后跟捕获的字符

要编辑文件,请尝试-i标记:

sed -i 'N;/\n.*hill/s/jill\(.*[^\n]\)/jerry\1/' file

答案 1 :(得分:3)

查找和替换的基本语法

<强>桑达

sed 's/word_to_find/word_to_replace/g' inputfile

要更新文件,请通过-i选项

sed -i 's/word_to_find/word_to_replace/g' inputfile

<强> GAWK

gawk -i inplace '{gsub(/find/,"replace"); print}' inputfile

<强> AWK

写入somefile然后重命名

awk '{ gsub(/find/,"replace"); print }' inputfile >outputfile

结束时的快捷方式1执行默认操作打印当前记录/行/行

awk 'gsub(/find/,"replace") + 1' inputfile >outputfile

- 编辑 -

<强>结果

$ cat f
jack and jill
climbs up a hill

$ awk '/hill/{gsub(/jill/,"jerry",prev);h=0;if(prev)print prev;print;prev="";next} h{print prev} {prev=$0; h=1}' f
jack and jerry
climbs up a hill

更好的可读性

   awk '/hill/{
               gsub(/jill/,"jerry",prev);
               h=0;
               if(prev)print prev;
               print;
               prev="";
               next
         }
        h{
               print prev
         }
         {
               prev=$0; h=1
         }
     ' f

经过

测试

<强>输入

$ cat f
jack and jill
climbs up a hill

jack and jill
climbs up a a
climbs up a hill

climbs up a a
climbs up a hill
jill
climbs up a hill
climbs up a hill

<强>输出

$ awk '/hill/{gsub(/jill/,"jerry",prev);h=0;if(prev)print prev;print;prev="";next} h{print prev} {prev=$0; h=1}' f
jack and jerry
climbs up a hill

jack and jill
climbs up a a
climbs up a hill

climbs up a a
climbs up a hill
jerry
climbs up a hill
climbs up a hill

答案 2 :(得分:2)

尝试以下:

解决方案1:我认为你必须只替换第一次出现的jill。

awk '/hill/{sub(/jill/,"jerry")}1'  Input_file

解决方案第二:我在考虑你必须替换所有出现的jill。

awk '/hill/{gsub(/jill/,"jerry")}1'   Input_file

解决方案3:如果您想将此新更改保存到Input_file本身,那么以下内容可能有所帮助。(放置sub / gsub以替换一次/多次出现的字符串)

awk '/hill/{sub(/jill/,"jerry")}1'  Input_file > temp_Input_file && mv temp_Input_file  Input_file

编辑:以上解决方案将在字符串jill和hill位于同一行时起作用,在OP的帖子编辑后,这些字符串似乎不在同一行,因此以下可能会有所帮助

awk '/jill/{val=$0;getline;if($0 ~ /hill/){sub(/jill/,"jerry",val);print val ORS $0};next} 1'   Input_file

答案 3 :(得分:2)

在awk中,考虑.preventDefault()hill是整个单词,而不是更长字符串的一部分。首先,一些测试数据:

jill

代码:

jack and jill
climbs up a hill
then jill silly
saws a hillbilly
cookin them jills
on a prec- hill

答案 4 :(得分:2)

使用vim这可以像

一样简单
:g                  starts a global command
/hill               searches for hill
/-1                 set the range to the previous line
s/jill/jerry        substitute jill with jerry

<强>击穿

jill

<强>其它

  • 如果要替换的前一行中有更多/g,请添加\<jill\>
  • 如果您只想匹配整个字词,请使用{{1}}
  • ...

答案 5 :(得分:1)

来自Linux.com:

Vim tips: The basics of search and replace

  

如果要搜索文本字符串并将其替换为另一个文本字符串,可以使用以下语法:[range] s / search / replace /。范围是可选的;如果您只运行:s / search / replace /,它将仅搜索当前行并仅匹配术语的第一个匹配项。

     

大多数时候,这还不够,所以你可以添加这样的范围:

     

:8,10秒/ search / replace / g

     

在该示例中,范围从第8行到第10行。我还添加了&#34;全局&#34;选项,告诉Vim替换一行中的每一个事件,而不仅仅是第一次出现。在不添加g的情况下,您的搜索将仅匹配任何给定行中字符串的第一个实例。

     

指定范围的另一种方法是进入可视模式并选择要搜索的行,然后按:进入命令模式。要从正常模式进入可视模式,请按v选择常规可视模式,或按V选择行选择,或按Ctrl-v选择块选择。然后在可视模式下选择范围并按:,然后按您要使用的搜索命令。

     

如果要搜索整个文件,可以使用%来表示该范围:

     

:%s​​ / search / replace / g

如果您愿意,也可以使用sed,该问题已经得到解答here

答案 6 :(得分:1)

为什么不用Perl?

perl -ne '$last =~ s/jill/jerry/ if(/hill/); print $last; $last = $_; END { print $last;}' file

稍微可读的版本:

$last =~ s/jill/jerry/ if($_ =~ /hill/);
print $last;
$last = $_;
END {
    print $last;
}