regex 如何使用sed在某个字符第一次出现后进行编辑?

1mrurvl1  于 2022-11-18  发布在  其他
关注(0)|答案(5)|浏览(135)

我创建了一个非常复杂的sed命令来删除与特定模式匹配的部分:

sed 's/...//Ig; s/...//Ig; s/...//Ig'

但是我发现我犯了一个错误,我应该只编辑第一次出现:之后的部分。如何修改这个sed命令和/或使用其他命令来实现它?
要编辑的行实际上是grep的输出,例如:

/foo/bar:foobar
/foobar/foo/bar:foo_bar
t3irkdon

t3irkdon1#

为了 简单 起见 , 我 假设 您 要 用 FOO 替换 第 一 个 : * * 之后 * * 出现 的 每个 foo

sed 'h           # save the current line in the hold space
     s/[^:]*://  # delete everything up to the marker
     s/foo/FOO/g # YOUR COMPLICATED COMMAND GOES HERE
     x           # swap pattern and hold space
     s/:.*/:/    # delete from the first : to the end in the original line
     G           # append hold space (: with whatever follows it)
     s/\n//' yourfile # remove the newline that comes with G

中 的 每 一 个
上述 代码 已 根据 在 评论 中 收到 的 建议 进行 了 更新 。
最初 的 答案 如下 所 示 , 虽然 在 本 例 中 有点 矫枉过正 , 但 它 表明 可以 在 sed\x0作为 一 个 " 标记 " , 通常 可以 假定 它 不在 文本 文件 中( 与 使用 _xxx_ 形成 对比 , _xxx_ 可能 已经 存在 于 文件 中 ) 。 * *( 第 二 个 版本 替换 了 foo * 在 * : 之前 的 出现 , 与 我 误读 问题 时 一致 。 * * )

sed 'h           # save the current line in the hold space
     s/:/\x0:/   # mark the first : by prepending a null character
     s/.*\x0//   # delete everything up to the marker
     x           # swap pattern and hold space
     s/:.*//     # delete from the first : to the end in the original line
     s/foo/FOO/g # YOUR COMPLICATED COMMAND GOES HERE
     G           # append hold space (: with whatever follows it)
     s/\n//' yourfile # remove the newline that comes with G

格式

vfh0ocws

vfh0ocws2#

awk在这里可以用作更好的替代:

awk 'BEGIN{FS=OFS=":"} {s=$1; $1=""; gsub(/a/, "@"); gsub(/o/, "0"); print s $0}' file
/foo/bar:f00b@r
/foobar/foo/bar:f00_b@r

这里我们使用:拆分输入,并将:之前的第一个字段保存在变量s中。然后我们运行几个gsub函数来完成所有替换,最后我们将保存的变量与行的其余部分一起打印。

p8h8hvxi

p8h8hvxi3#

这 可能 对 你 有用 ( GNU sed ) :

sed 's/:/\n&/;h;s/foo/FOO/g;s/bar/BAR/g;y/-/_/;H;g;s/\n.*\n//' file

中 的 每 一 个
在 第 一 个 : 之前 引入 一 个 换行符 。
将 结果 复制 到 保留 空间 ( HS ) 。
全局 替换/转换 一 次 或 多次 。
将 模式 空间 ( PS ) 附加 到 HS 。
将 PS 更换 为 HS 。
删除 换行符 和 换行符 之间 的 所有 内容 。

a5g8bdjr

a5g8bdjr4#

首先将grep输出的每一行拆分为2行,然后在偶数行上执行sed命令。
看起来就像

grep "something" list_of_file |
  sed 's/:/\n/' |
  sed '0~2s/...//Ig; 0~2s/...//Ig; 0~2s/...//Ig' |
  paste -d":" - -

对于0~2,您将告诉sed仅在偶数行上操作。
示例:

grep -E "root|127" /etc/{passwd,hosts} |
   sed 's/:/\n/' |
   sed -r '0~2s/([0,o])/==\1==/g' | 
   paste -d":" - -

输出:

/etc/passwd:r==o====o==t:x:==0==:==0==:r==o====o==t:/r==o====o==t:/bin/bash
/etc/hosts:127.==0==.==0==.1    l==o==calh==o==st
c9qzyr3d

c9qzyr3d5#

您可以尝试Perl替代方法。下面是一个使用正lookbehind的解决方案

$ cat grep_out.dat
/foo/bar:foobar
/foobar/foo/bar:foo_bar
$ perl -pe ' s/(?<=:)(foo)/\U\1/g ' grep_out.dat
/foo/bar:FOObar
/foobar/foo/bar:FOO_bar
$

相关问题