【问题标题】:How to replace first occurrence with sed?如何用sed替换第一次出现?
【发布时间】:2019-02-13 00:14:32
【问题描述】:

我有很多名字的文件:我只想替换第一个

sed -i "s/\(name:\).*/\1 ${NEW_VALUE}/" ./myFile

Input
-  martin:
    name: Martin D'vloper
    job: Developer
    skills:
      - python
      - perl
      - pascal
-  tabitha:
    name: Tabitha Bitumen
    job: Developer
    skills:
      - lisp
      - fortran
      - erlang

输出仅更改名字 Martin D'vloper

-  martin:
        name: NEW VALUE!!!
        job: Developer
        skills:
          - python
          - perl
          - pascal
    -  tabitha:
        name: Tabitha Bitumen
        job: Developer
        skills:
          - lisp
          - fortran
          - erlang

它改变了所有的名字

我看到了一些语法不同的东西

sed '0,/pattern/s/pattern/replacement/' filename

但我无法将 sed 更改为此,因为动态值 你能告诉我如何用我的语法只替换第一个吗?

【问题讨论】:

  • 如果您能提供输入和预期输出的样本,我们的生活会更轻松,请将它们添加到您的帖子中并让我们知道吗?
  • 更新了输入输出
  • 我删除了我的答案(sed -z "s/name:[^\n]*/name: $NEW_VALUE/"),因为这个问题确实是重复的。现在可以找到我的答案here
  • 如果总是第 2 行:sed -r '2s/(name:).*/\1 NEW VALUE!!!/' file

标签: bash awk sed


【解决方案1】:

这应该做你想做的:

sed -i "0,/name:/{s/name:.*/name: ${NEW_VALUE}/}" ./myFile

它找到name: 的第一个匹配项,然后进行替换,即将'name: followed by any characters'(.* 表示任何字符序列)替换为'name: ${NEW_VALUE}' 其中 NEW_VALUE 是您示例中的动态变量。

来自 man sed

0,地址2

从“匹配的第一个地址”状态开始,直到找到 addr2。这个 类似于 1,addr2,除了如果 addr2 匹配第一个 输入 0,addr2 形式的行将位于其范围的末尾, 而 1,addr2 形式仍将位于其范围的开头。 这仅在 addr2 是正则表达式时有效。

【讨论】:

  • 你能解释一下吗?
  • 为什么我们需要第一个 /name/{ ?
  • 它应该是名称:更正它,它基本上说 find first name: in file 并执行指定的替换,在答案中添加了 man 摘录
【解决方案2】:

如果您对awk 没问题,请尝试关注。

awk '/name/ && ++count==1{sub(/name:.*/,"name: NEW VALUE!!!")} 1'  Input_file

如果您有一个 shell 变量,并且您想将其值添加到 awk 代码中,请尝试以下操作。

val="new_vaue"
awk -v value="$val" '/name/ && ++count==1{sub(/name:.*/,"name: "value)} 1'  Input_file

如果您想将输出保存到 Input_file 本身,请将> temp_file && mv temp_file Input_file 附加到上面的代码中。

【讨论】:

  • @user1365697,请参阅我的第二个解决方案,您可以用变量(从 shell 到 awk)替换值,如果这有帮助,请告诉我。
【解决方案3】:

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

sed -i "/\(name:\).*/{s//\1 ${NEW_VALUE}/;:a;n;ba}" ./myFile

匹配name:,替换新值,然后读取并打印文件的其余部分。

或替代:

sed -z -i 's/\(name:\).*/\1 '"${NEW_VALUE}"'/M' file

注意将M 标志添加到替换命令以将.* 限制在一行内。

【讨论】:

  • 我有 GNU sed 版本 4.2.1,它没有 -z 选项。
  • 第一个选项的解释:当找到模式“name:”后跟任意数量的字符时,将“name:”保存为第一个子表达式(/\(name:\).*/),然后执行这些命令({):替换(s)第一个子表达式(\1)匹配的任何内容(\1)后跟一个空格以及变量NEW_VALUE(*space*${NEW_VALUE}/)中保存的内容然后(;)在这个命令中创建标签'a'(:a)然后(;)打印并转到下一行,如果没有更多则退出(n)然后( ;) 分支回到标签 a(ba)。匹配模式的命令结束(})。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-27
  • 2021-12-05
  • 2015-05-30
  • 2015-09-01
  • 2016-12-22
相关资源
最近更新 更多