【问题标题】:Replace one matched pattern with another in multiline text with sed用 sed 在多行文本中用另一个匹配的模式替换一个匹配的模式
【发布时间】:2021-04-02 10:21:27
【问题描述】:

我有这个文本的文件:

mirrors:
  docker.io:
    endpoint:
      - "http://registry:5000"
  registry:5000:
    endpoint:
      - "http://registry:5000"
  localhost:
    endpoint:
      - "http://registry:5000"

我需要在 POSIX shell 脚本(不是 bash)中用这个文本替换它:

mirrors:
  docker.io:
    endpoint:
      - "http://docker.io"
  registry:5000:
    endpoint:
      - "http://registry:5000"
  localhost:
    endpoint:
      - "http://localhost"

应该在所有没有硬编码名称的地方动态地进行替换。我的意思是我们应该从第一行(“docker.io”、“registry:5000”、“localhost”)获取子字符串,并在第三行用它替换子字符串“registry:5000”。

我已经弄清楚了正则表达式,它将它分成 5 个组:(^ )([^ ]*)(:[^"]*"http:\/\/)([^"]*)(")

然后我尝试使用 sed 打印组 2 而不是 4,但这不起作用:sed -n 's/\(^ \)\([^ ]*\)\(:[^"]*"http:\/\/\)\([^"]*\)\("\)/\1\2\3\2\5/p'

请帮忙!

【问题讨论】:

    标签: sed sh posix portability


    【解决方案1】:

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

    sed -E '1N;N;/\n.*endpoint:.*\n/s#((\S+):.*"http://)[^"]*#\1\2#;P;D' file 
    

    在文件中打开一个三行窗口。

    如果第二行包含endpoint:,则将http://之后的最后一段文字替换为:之前的第一段文字

    打印/删除窗口的第一行,然后通过附加下一行来补充三行窗口。

    重复直到文件结束。

    【讨论】:

    • 完美!谢谢!
    【解决方案2】:

    Awk 将是一个更好的选择,将要更改的字符串作为变量 str 和要更改的部分(“docker.io”或“localhost”或“registry:5000”)传递,等等:

    awk -v findstr=" docker.io" -v str="http://docker.io" '
    $0 ~ findstr { dockfound=1 # We have found the section passed in findstr and so we set the dockfound marker
                 } 
    /endpoint/ && dockfound==1 { # We encounter endpoint after the dockfound marker is set and so we set the found marker
                   found=1;
                   print;
                   next 
                  } 
     found==1 && dockfound==1 { # We know from the found and the dockfound markers being set that we need to process this line
                   match($0,/^[[:space:]]+-[[:space:]]"/); # Match the start of the line to the beginning quote
                   $0=substr($0,RSTART,RLENGTH)str"\""; # Print the matched section followed by the replacement string (str) and the closing quote
                   found=0; # Reset the markers
                   dockfound=0 
                   }1' file
    

    一个班轮:

    awk -v findstr=" docker.io" -v str="http://docker.io" '$0 ~ findstr { dockfound=1 } /endpoint/ && dockfound==1 { found=1;print;next } found==1 && dockfound==1 { match($0,/^[[:space:]]+-[[:space:]]"/);$0=substr($0,RSTART,RLENGTH)str"\"";found=0;dockfound=0 }1' file
    

    【讨论】:

    • 无效,因为替换应该在所有没有硬编码名称的地方动态完成。
    • 我的意思是我们应该从第一行获取子字符串(“docker.io”、“registry:5000”、“localhost”)并用它替换子字符串“registry:5000”第三行。
    • 好的。我已经修改了答案。它现在也需要将该部分更改为变量。
    猜你喜欢
    • 2020-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-12
    • 1970-01-01
    • 1970-01-01
    • 2018-04-30
    • 2020-01-14
    相关资源
    最近更新 更多