我目前有一个 sed 命令,我想对以下类型的文本进行操作:
user:
ensure: 'present'
uid: '666'
gid: '100'
home: '/home/example'
comment: ''
password_max_age: '99999'
password_min_age: '0'
shell: '/bin/false'
password: ''
Run Code Online (Sandbox Code Playgroud)
我可以用这个命令得到我想要的结果类型:
sed '/user:/!b;n;n;n;n;n;n;n;n;n;s/.*/\t\tpassword: \x27\!\!\x27/g'
user:
ensure: 'present'
uid: '666'
gid: '100'
home: '/home/example'
comment: ''
password_max_age: '99999'
password_min_age: '0'
shell: '/bin/false'
password: '!!'
Run Code Online (Sandbox Code Playgroud)
该命令的问题在于它user:
是静态的。我希望能够遍历用户列表并在 sed 命令中使用 bash 变量而不是特定用户。不过,要做到这一点,我需要使用双引号而不是单引号。但是,当我使用此命令时:
sed "/user:/!b;n;n;n;n;n;n;n;n;n;s/.*/\t\tpassword: \x27\!\!\x27/g"
它抱怨“!” 在!b
我正在使用的sed 命令中。(因为 bash 试图解释它)但是,如果我像这样转义它:
sed "/user:/\!b;n;n;n;n;n;n;n;n;n;s/.*/\t\tpassword: \x27\!\!\x27/g"
然后我收到这个错误:
sed:-e 表达式 #1,字符 6:未知命令:`\'
我怎样才能让它发挥作用?
这是 shell 语言语法的一个重要但经常被遗忘的方面。一个人“引用论点”的心理模型实际上是简单和错误的。一个引用需要引用的东西,并且只需要成为最终作为单个参数的一部分。
而这正是您在这里需要做的。具有讽刺意味的是,第一个现已删除的答案非常接近。
您想要sed
作为它执行的实际单个参数的最后一个字符串是
/user:/!b;n;n;n;n;n;n;n;n;n;s/.*/\t\t密码:\x27!!\x27/g与所述
user
部分根据实际的用户名不同。但是要到达这里,您不需要对整个参数使用一个单引号方案。你可以从部分建立论点。
使用双引号的,你需要进行参数扩展,以及单引号,你需要历史扩展到地区的部分不会发生:
读时 -ri 做 sed -e '/'"$i"':/!b;n;n;n;n;n;n;n;n;n;s/.*/\t\tpassword: \x27!!\x27 /g' puppet-users.yaml > puppet-users{new}.yaml mv puppet-users{new}.yaml puppet-users.yaml 完成 < user_list.txt
这是:
/
。$i
受参数扩展(当然还有所有其他扩展和替换)影响的双引号字符。:/!b;n;n;n;n;n;n;n;n;n;s/.*/\t\tpassword: \x27!!\x27/g
不受历史扩展影响的单引号字符。字段拆分只发生在不带引号的字符上;和有没有这样的位置好,所以这是所有的一个领域,成为所有一个参数的sed
命令。
一旦你这样做了,你会发现你在做的事情中使用了太多的 TAB 字符。☺
sed
不是这项工作的正确工具。也确实不是awk
,就像在第二个现已删除的答案中一样。从长远来看,如果手头的任务变得不那么琐碎,那么使用适当的 YAML 解析器(例如 Python 的 yaml 模块)解析 YAML 会更好。
这是一个简单的单线,带有适合该工作的工具,例如各种yq
工具,其用法大致是(因为,唉,它们都不同):
读时 -ri 做 yq < puppet-users.yaml "$i".password="'\!\!'" > puppet-users{new}.yaml mv puppet-users{new}.yaml puppet-users.yaml 完成 < user_list.txt