使用 sed 编辑任意一个匹配模式的出现

使用 sed 编辑任意一个匹配模式的出现

一行开始带有 Fred Flintstone 的应附加一些字符串。查找 Fred Flintstone 的指定出现位置并将其附加。

如何使用此命令任何发生的情况这样的模式?我试过

sed '/Fred Flintstone/ s/$/ someString/2' filename

显然上面的方法不起作用。它对所有情况都有效,但对特定情况无效。(比如我想替换第一个、第二个或第三个 [其中任何一个])

示例文件1:

Fred Flintstone 
Johnson Stone
Fred Flintstone
Fred Flintstone
Michael Clark

所需输出文件 1:

Fred Flintstone 
Johnson Stone
Fred Flintstone someString
Fred Flintstone
Michael Clark

答案1

尽管您已经提到过sed,但这些都是awk-y 任务:

awk -v pat="Fred Flintstone" '$0 ~ pat {count++;\
               if (count == 2) { $0 = $0" someString" ;} ;}; 1' file.txt
  • -v pat="Fred Flintstone"将要匹配的正则表达式模式保存为表达式pat内部使用的变量awk

  • $0 ~ pat检查记录是否pat匹配;如果匹配,则count变量增加 1,如果count为 2,则记录重置为具有当前内容加上someString( {count++; if (count == 2) { $0 = $0" someString" ;} ;})

  • 1 是一个习语;因为它是真谛,所有记录都将被打印

例子:

% cat file.txt
Fred Flintstone
Johnson Stone
Fred Flintstone
Fred Flintstone
Michael Clark

% awk -v pat="Fred Flintstone" '$0 ~ pat {count++; if (count == 2) { $0 = $0" someString" ;} ;}; 1' file.txt
Fred Flintstone
Johnson Stone
Fred Flintstone someString
Fred Flintstone
Michael Clark

答案2

这个简单的sed命令允许您有选择地进行更改,而无需使用循环(它使用分支到结尾)或需要 GNU 扩展或一次读取整个文件:

sed -r '/Fred Flintstone/ {x; s/$/#/; /^#{2}$/ {x; s/.*/& someString/; b}; x}'

解释:

  • -r- 使用扩展的正则表达式
  • /Fred Flintstone/- 对于符合此模式的行:
    • x- 交换模式空间和保持空间(激活计数器)
    • s/$/#/- 在计数器中添加一个字符
    • /^#{2}$/- 当计数器长度为 2 时(替换任意值)
      • x交换模式空间和保持空间(激活计数的输入行)
      • s/.*/& someString/- 将字符串附加到所需的行
      • b- 跳至此行处理的末尾,以便打印
    • x- 交换模式空间和保持空间(激活与字符串匹配但不匹配计数的行)

解释中的缩进级别表示花括号嵌套的级别。

所有其他行均不经处理而直接通过并被打印。

答案3

修改答案以防止在使用时在反斜杠以及斜杠、引号上注入代码awk变量或awk -v variable ...shellawk '...' variable="$value"awk-v variable=对通过或 shell传递的值进行 C 转义序列处理variable=$value;因此 shell将更variable='\\n'改为\nawk)。

pattern="${patt//\\/\\\\}" awk '
    $0 ~ ENVIRON["pattern"]{ seen++ } seen==2 { $0 = $0 "something"};1' infile

对于以下输入和图案

another break line
Johnson Stone
\"Fred //\\Flintstone' SOMETHING will goes here ...
\"Fred //\\Flintstone'
Michael Clark

模式位于名为patt

$ echo "$patt"
\"Fred //\\Flintstone'

输出为:

\"Fred //\\Flintstone'
another break line
Johnson Stone
\"Fred //\\Flintstone' SOMETHING will goes here ...something
\"Fred //\\Flintstone'
Michael Clark

解释:

稍后您可能需要将something字符串作为变量传递,并且需要使用类似的东西edit=$somesting并在那里使用ENVIRON["edit"]

pattern="${patt//\\/\\\\}" edit="$something" awk '
    $0 ~ ENVIRON["pattern"]{ seen++ } seen==2 { $0 = $0 ENVIRON["edit"]};1' infile

答案4

另一个用例ex,POSIX 指定的文件编辑器

(它是 的前身,vi并且现在仍是 的一部分vi。)

printf '%s\n' '0/Fred Flintstone///s/$/ someString/' x | ex filename

这里的神奇之处在于,与 Sed、Awk 和类似工具不同,ex它不会在每一行上运行代码。您可以移动光标、发出命令等。

在这种情况下,我们给出一个行号0(确保第一行的 Fred Flintstone 会被考虑在内),后跟一个正则表达式,/Fred Flintstone/它引用文件中与该正则表达式匹配的第一行,后跟另一个正则表达式//,该正则表达式为空,重用最后一个正则表达式,因此引用第二文件中匹配的行;然后我们使用s您已经知道的命令。

x命令表示保存所有更改并退出。

我们用来printf向输入命令ex

相关内容