同时递归搜索和替换值
Searching and replacing values recursively in the same time
我有一个 Ansible playbook 文件夹,我想在其中 grep 特定的 YAML 块并用 playbook 文件夹中的值替换其中一个 Jinja2 变量。
例如:
grep -R -A 35 -w -h 'test_profiles:' .
test_profiles:
- name: test_1
source: '{{ service_name }}'
所以我想用它的值
插入 service_name
变量
我尝试的是对 service_name
进行 grep,但无法找到一种方法将变量递归替换为每个剧本文件夹的各自搜索结果
文件夹结构:
- 剧本 1
- main.yml < 包含
service_name
值
- 任务
- file.yml < 包含
test_profiles
块,我需要替换其中的 service_name
- 剧本 2
- main.yml
- 任务
- file.yml
- ...等等
main.yml 来自剧本 1 示例:
---
service_name: 'service 1'
main.yml 来自剧本 2 示例:
---
service_name: 'service 2'
file.yml 来自剧本 1 示例:
---
test_profiles:
- name: test_1
source: '{{ service_name }}'
other_header:
key: value
file.yml 来自剧本 2 示例:
---
test_profiles:
- name: test_2
source: '{{ service_name }}'
another_header:
another_key: value
预期结果:
test_profiles:
- name: test_1
source: 'service 1'
test_profiles:
- name: test_2
source: 'service 2'
test_profiles:
- name: test_3
source: 'service 3'
grep 命令我试图获取 service_name
变量:
grep -R -oE 'service_name=([a-zA-Z]*-*[a-zA-Z]*)*|service_name:(\s*[a-zA-Z]*-*[a-zA-Z]*)*' .
但我找不到一种方法来组合这两个命令,以产生上述预期结果。
此解决方案每个剧本运行一个 awk
。解析 main.yml
并存储 service_name
的值。解析第二个文件并仅打印替换了变量的行块(以 test_profiles:
开始并以空行或仅以 white-space 字符结束)。您从目录结构的根目录执行以下脚本。
#!/bin/bash
for d in playbook*; do
[[ -f "$d"/main.yml ]] && [[ -f "$d"/tasks/file.yml ]] || continue
awk -F"'" 'FNR==NR && /^service_name:/{s=;next} {FS=OFS}
/test_profiles:/ {f=1}
f {gsub("{{ service_name }}",s)}
f && (NF==0) {f=0}
f' "$d"/main.yml "$d"/tasks/file.yml
done
此外,如果 main.yml
中没有值,则会为 {{ service_name }}
打印空字符串,如果这不是功能而是错误,我们可以更改它。任何没有两个文件的剧本都会被忽略。
参考:
How to read two files with awk (NR==FNR
)
gsub and the other GNU awk
string functions
How to print using a flag a block between start and end pattern
我有一个 Ansible playbook 文件夹,我想在其中 grep 特定的 YAML 块并用 playbook 文件夹中的值替换其中一个 Jinja2 变量。
例如:
grep -R -A 35 -w -h 'test_profiles:' .
test_profiles:
- name: test_1
source: '{{ service_name }}'
所以我想用它的值
插入service_name
变量
我尝试的是对 service_name
进行 grep,但无法找到一种方法将变量递归替换为每个剧本文件夹的各自搜索结果
文件夹结构:
- 剧本 1
- main.yml < 包含
service_name
值 - 任务
- file.yml < 包含
test_profiles
块,我需要替换其中的service_name
- file.yml < 包含
- main.yml < 包含
- 剧本 2
- main.yml
- 任务
- file.yml
- ...等等
main.yml 来自剧本 1 示例:
---
service_name: 'service 1'
main.yml 来自剧本 2 示例:
---
service_name: 'service 2'
file.yml 来自剧本 1 示例:
---
test_profiles:
- name: test_1
source: '{{ service_name }}'
other_header:
key: value
file.yml 来自剧本 2 示例:
---
test_profiles:
- name: test_2
source: '{{ service_name }}'
another_header:
another_key: value
预期结果:
test_profiles:
- name: test_1
source: 'service 1'
test_profiles:
- name: test_2
source: 'service 2'
test_profiles:
- name: test_3
source: 'service 3'
grep 命令我试图获取 service_name
变量:
grep -R -oE 'service_name=([a-zA-Z]*-*[a-zA-Z]*)*|service_name:(\s*[a-zA-Z]*-*[a-zA-Z]*)*' .
但我找不到一种方法来组合这两个命令,以产生上述预期结果。
此解决方案每个剧本运行一个 awk
。解析 main.yml
并存储 service_name
的值。解析第二个文件并仅打印替换了变量的行块(以 test_profiles:
开始并以空行或仅以 white-space 字符结束)。您从目录结构的根目录执行以下脚本。
#!/bin/bash
for d in playbook*; do
[[ -f "$d"/main.yml ]] && [[ -f "$d"/tasks/file.yml ]] || continue
awk -F"'" 'FNR==NR && /^service_name:/{s=;next} {FS=OFS}
/test_profiles:/ {f=1}
f {gsub("{{ service_name }}",s)}
f && (NF==0) {f=0}
f' "$d"/main.yml "$d"/tasks/file.yml
done
此外,如果 main.yml
中没有值,则会为 {{ service_name }}
打印空字符串,如果这不是功能而是错误,我们可以更改它。任何没有两个文件的剧本都会被忽略。
参考:
How to read two files with awk (NR==FNR
)
gsub and the other GNU awk
string functions
How to print using a flag a block between start and end pattern