一行开始带有 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'
改为\n
awk)。
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
解释:
这
pattern="${patt//\\/\\\\}"
将转义变量中的所有反斜杠$patt
,因为 [“the '~' operator does pattern matching, treating the right hand operand as an (extended) regular expression, and the left hand one as a string
“经过穆鲁],你需要逃离所有 ERE 中的特殊字符然后。这
$0 ~ ENVIRON["pattern"]{ seen++ }
将检查当前行是否与匹配pattern
,然后将值增加seen++
一次。检查
seen==2 { $0 = $0 "something"}'
是否有第二行与pattern
上述结果(现在seen==2
)匹配,然后在该行末尾附加字符串“somestring”。1
最后的(或任何真实的陈述)是使awk默认打印。
稍后您可能需要将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
。