对一个匹配的 sed 组使用不同的 sed 替换

对一个匹配的 sed 组使用不同的 sed 替换

我是一名经验丰富的软件开发人员,但现在才回过头来学习 sed 技能。

text.txt我有一个包含以下格式的行的文件:

blah blah blah
key-1:foo-bar
key-2:foo-baz
more blah blah

我想分离出键/值对 sushc 作为key-1foo-bar并将它们发送给命令do-something,但我想转换foo-barfoo_bar

要提取键/值对,目前我有这样的事情:

sed -nE 's/([^:]+):(.+)/\1 \2/p' test.txt

这将打印:

key-1 foo-bar
key-2 foo-baz

到目前为止一切顺利。现在,如果我想将其传递给do-something,我想我可以做这样的事情并将其传送到xargs或类似的东西:

sed -nE 's/([^:]+):(.+)/do-something -a \1 -b \2/p' test.txt | xargs #something or another

我还没有查看 xargs 部分。在查看之前,我想知道:我怎样才能-用替换_,但只能在第二个 sed 匹配组中,而不是第一个?

或者有没有更简单的 *nix 工具我可以使用?(我也欢迎有关 xargs 部分的建议do-something。)谢谢。

答案1

GNUsed允许你替换-一行中第二次及之后出现的 。像这样:

<test.txt sed -nE '/[^:]+:/ {s/-/_/2g; s/:/ / p}'

对于您的示例数据,这种方法可能就足够了;但是,如果第二个-在键中(key-3-4:foo)或者第一个-在值中(key5:bar-baz),则它将会失败。

可以采用一种通用方法来识别密钥并保持其完好无损。我的想法是:

<test.txt sed -nE '/^[^:]+:/ {
   h
   s/:.*/ /
   x
   s/[^:]+://
   s/-/_/g
   H
   g
   s/\n//
   p
   }'

解释:

  • 将一行加载到模式空间中,因为这就是它的sed作用。
  • /^[^:]+:/– 匹配以一个或多个非冒号开头,后跟一个冒号的行;其余代码被分组,{}这意味着对于匹配的行将执行整个组,而对于不匹配的行将被忽略。
  • h– 将模式空间复制到保存空间。
  • s/:.*/ /– 将冒号(由于初步匹配,因此保证存在)及其后的所有内容替换为空格字符。这将匹配模式空间中的第一个冒号,因为这是正则表达式的工作方式。结果,模式空间包含键和空格。
  • x– 交换保持空间和模式空间的内容。现在整行又回到了模式空间中;键和空间安全地保存在保持空间中。
  • s/[^:]+://– 删除模式空间中第一个冒号之前的所有内容。剩下的就是值。
  • s/-/_/g– 将所有出现的 替换-_
  • H– 将模式空间附加到保留空间。旧内容(键加空格)和附加字符串(更改后的值)之间将有一个换行符。
  • g– 将保持空间复制到模式空间。
  • s/\n//– 删除上述换行符。
  • p– 打印当前模式空间。

笔记:

  • 保留空间从一行到另一行仍然存在,但是h每次我们需要重新使用它时都会覆盖它(),因此无需明确清除它。
  • 问问自己是否想g加入s/-/_/g

相关内容