使用 Bash 编辑 YAML 文件

Mor*_*nor 10 python bash awk yaml sed

我正在尝试编辑以下 YAML 文件

db:
  host: 'x.x.x.x.x'
  main:
    password: 'password_main'
  admin:
    password: 'password_admin'
Run Code Online (Sandbox Code Playgroud)

为了编辑该host部分,我开始使用它

sed -i "/^\([[:space:]]*host: \).*/s//\1'$DNS_ENDPOINT'/" config.yml
Run Code Online (Sandbox Code Playgroud)

但是我找不到更新mainadmin(它们是不同的值)的密码的方法。

我试图玩弄\n[[:space:]],得到了不同的口味:

sed -i "/^\([[:space:]]*main:\n*[[:space:]]*password: \).*/s//\1'$DNS_ENDPOINT'/" config.yml
Run Code Online (Sandbox Code Playgroud)

但从来没有让它工作。非常感谢任何帮助!

编辑- 要求:没有外部二进制文件/工具。只是好 ol' bash。

Ted*_*gmo 9

由于您不想安装yq,因此可以使用您很可能已经安装的

以下是基本原理:

#!/usr/bin/python

import yaml

with open("file.yml") as f:
    y=yaml.safe_load(f)
    y['db']['admin']['password'] = 'new_admin_pass'
    print(yaml.dump(y, default_flow_style=False, sort_keys=False))
Run Code Online (Sandbox Code Playgroud)

输出:

db:
  host: x.x.x.x.x
  main:
    password: password_main
  admin:
    password: new_admin_pass

Run Code Online (Sandbox Code Playgroud)

可以放入脚本的与单行代码类似的一段代码如下所示(并产生相同的输出):

python -c 'import yaml;f=open("file.yml");y=yaml.safe_load(f);y["db"]["admin"]["password"] = "new_admin_pass"; print(yaml.dump(y, default_flow_style=False, sort_keys=False))'
Run Code Online (Sandbox Code Playgroud)

  • @RavinderSingh13 不客气!它需要一些编辑来替换硬编码字符串,但在编辑 YAML 文件时它应该是一个很好的基础。 (2认同)
  • 确实非常好的答案,为我提供了Python的稳健性。 (2认同)

0st*_*ne0 8

注意:yq使用像( 或)这样的 YAML 解析器yq将是一种更可靠的解决方案。


的帮助来更改“预定义”行,如下所示;

/tmp/config.yml

db:
  host: 'x.x.x.x.x'
  main:
    password: 'password_main'
  admin:
    password: 'password_admin'
Run Code Online (Sandbox Code Playgroud)
  1. 获取“旧密码”所在的行号:
    grep -n 'password_admin' /tmp/config.yml | cut -d ':' -f1
    
    Run Code Online (Sandbox Code Playgroud)

    6

  2. 然后,使用sed您的新密码覆盖该行:
    sed -i '6s/.*/    password: \'new_admin_pass\'/' /tmp/config.yml
    
    Run Code Online (Sandbox Code Playgroud)

新文件现在如下所示:

grep -n 'password_admin' /tmp/config.yml | cut -d ':' -f1
Run Code Online (Sandbox Code Playgroud)

笔记

  • 请记住,密码中的任何特殊字符( &\、 )都会导致行为不当!/sed

  • 如果缩进发生变化,这可能会失败,因为 YAML 关心缩进。就像我上面提到的,使用 YAML 解析器将是一个更可靠的解决方案!

  • 如果新密码包含反向引用元字符(如“&”或“\1”),或者包含分隔符“/”或转义字符“my\new\pass”或其他字符,则会失败。只要你的密码始终严格是字母数字,你应该没问题,但如果不是那么 YMMV。不过,您不需要 grep+cut+sed - 一个简单的 awk 脚本即可完成这项工作。这并不是说这依赖于您知道旧的管理员密码,而您真正想要的只是将管理员(或主)密码更改为新值,无论以前是什么。 (4认同)
  • ...我刚刚意识到,如果“main:”密码恰好与“admin:”密码相同,或者如果该管理员密码恰好也出现在文件中的其他位置,那么它也会失败。 (3认同)

anu*_*ava 5

绝不是可靠的,yqawk如果您的 yaml 文件结构与问题中的显示方式相同,您可以使用它:

pw='new_&pass'
awk -v pw="${pw//&/\\\\&}" '/^[[:blank:]]*main:/ {
   print
   if (getline > 0 && $1 == "password:")
      sub(/\047[^\047]*\047/, "\047" pw "\047")
} 1' file
Run Code Online (Sandbox Code Playgroud)
db:
  host: 'x.x.x.x.x'
  main:
    password: 'new_&pass'
  admin:
    password: 'password_admin'
Run Code Online (Sandbox Code Playgroud)


Ed *_*ton 5

$ awk -v new="'sumthin'" 'prev=="main:"{sub(/\047.*/,""); $0=$0 new} {prev=$1} 1' file
db:
  host: 'x.x.x.x.x'
  main:
    password: 'sumthin'
  admin:
    password: 'password_admin'
Run Code Online (Sandbox Code Playgroud)

或者,如果您的新文本可以包含您不希望扩展的转义序列(例如\t\n),这在设置密码时似乎很可能,那么:

new="'sumthin'" awk 'prev=="main:"{sub(/\047.*/,""); $0=$0 ENVIRON["new"]} {prev=$1} 1' file
Run Code Online (Sandbox Code Playgroud)

请参阅如何在 awk 脚本中使用 shell 变量?为什么/如何使用ENVIRON[]访问 shell 变量而不是在第二个脚本中设置 awk 变量。