У меня есть этот файл, и я знаю значение LOC, например /oracle/19.0.0. Хотите получить значение HOME NAME=, соответствующее значение будет OraDB19Home1.
Посмотрел поиск, но не смог заставить его полностью работать. Цените любую помощь.
<?xml version = '1.0' encoding = 'UTF-8' standalone = 'yes'?>
<!-- Copyright (c) 1999, 2022, Oracle. All rights reserved. -->
<!-- Do not modify the contents of this file by hand. -->
<INVENTORY>
<VERSION_INFO>
<SAVED_WITH>13.9.4.0.0</SAVED_WITH>
<MINIMUM_VER>2.1.0.6.0</MINIMUM_VER>
</VERSION_INFO>
<HOME_LIST>
<HOME NAME = "OraHome1" LOC = "/oracle/agent/agent13.4" TYPE = "O" IDX = "3"/>
<HOME NAME = "OraDB19Home1" LOC = "/oracle/19.0.0" TYPE = "O" IDX = "2"/>
</HOME_LIST>
</INVENTORY>
Это почти тривиально сделать с awk:
Форматируется как файл сценария:
/<HOME NAME=.*TYPE=.*IDX=/ {
if ($3 == "LOC=\"/oracle/19.0.0\"") {
split($2, a, /"/);
print a[2];
exit;
}
}'
Командная строка:
cat your_input_file | awk '/<HOME NAME=.*TYPE=.*IDX=/{ if ($3 == "LOC=\"/oracle/19.0.0\"") { split($2, a, /"/); print a[2]; exit } }'
Вероятно, вы можете относительно легко преобразовать это во что-то подобное в python.
awk -v loc='LOC = "/oracle/19.0.0"' '
index($0,loc){
print gensub(/^.*NAME = "([^"]*)".*$/,"\\1",1)
}
' inputfile
или
awk -F'=|"' -v loc='LOC = "/oracle/19.0.0"' 'index($0,loc){print $3}' inputfile
awk -F'=|"' -v loc = "/oracle/19.0.0" '/ LOC = "[^"]*" / && $6 == loc {print $3}' inputfile
Выход
OraDB19Home1
Для меня вариант использования выглядит как
Похожие вопросы и ответы
Предполагается, что неблагоприятная структура данных в вашем файле примера конфигурации остается прежней, и вы ищете grep
подход в Ansible.
- name: Gather home directory
shell:
cmd: "grep '{{ VERSION }}' inventory.xml | cut -d '=' -f 2 | cut -d ' ' -f 1 | tr -d '"'"
register: home_dir
Как действовать дальше?
Если такие поиски необходимы часто или в большем масштабе, можно воспользоваться преимуществами реализации конкретного решения.
Если установка ansible.utils.collection и библиотеки Python xmltodict возможна или уже доступна, вам обязательно следует воспользоваться рекомендуемым решением от Владимира Ботки фильтра from_xml — преобразовать заданную строку XML в собственный словарь Python путем преобразования XML в YAML перед дальнейшей обработкой.
В противном случае вы можете попробовать
Примеры пользовательских модулей
Спасибо! Цените помощь. Пытался избежать cmd/shell и сделать это изначально в ansbile.
Given the XML
shell> cat inventory.xml
<?xml version = '1.0' encoding = 'UTF-8' standalone = 'yes'?>
<!-- Copyright (c) 1999, 2022, Oracle. All rights reserved. -->
<!-- Do not modify the contents of this file by hand. -->
<INVENTORY>
<VERSION_INFO>
<SAVED_WITH>13.9.4.0.0</SAVED_WITH>
<MINIMUM_VER>2.1.0.6.0</MINIMUM_VER>
</VERSION_INFO>
<HOME_LIST>
<HOME NAME = "OraHome1" LOC = "/oracle/agent/agent13.4" TYPE = "O" IDX = "3"/>
<HOME NAME = "OraDB19Home1" LOC = "/oracle/19.0.0" TYPE = "O" IDX = "2"/>
</HOME_LIST>
</INVENTORY>
Прочитайте файл и конвертируйте XML в YAML
inv_xml: "{{ lookup('file', 'inventory.xml') }}"
inv_yml: "{{ inv_xml|ansible.utils.from_xml }}"
дает
inv_yml:
INVENTORY:
HOME_LIST:
HOME:
- '@IDX': '3'
'@LOC': /oracle/agent/agent13.4
'@NAME': OraHome1
'@TYPE': O
- '@IDX': '2'
'@LOC': /oracle/19.0.0
'@NAME': OraDB19Home1
'@TYPE': O
VERSION_INFO:
MINIMUM_VER: 2.1.0.6.0
SAVED_WITH: 13.9.4.0.0
Создайте словарь LOC и NAME
loc_name: "{{ inv_yml.INVENTORY.HOME_LIST.HOME|
items2dict(key_name='@LOC',
value_name='@NAME') }}"
дает
loc_name:
/oracle/19.0.0: OraDB19Home1
/oracle/agent/agent13.4: OraHome1
Тогда поиск тривиален
loc: '/oracle/19.0.0'
name_of_loc: "{{ loc_name[loc] }}"
дает
name_of_loc: OraDB19Home1
, или в цикле
- debug:
msg: "The name of LOC {{ item }} is {{ loc_name[item] }}"
loop:
- '/oracle/19.0.0'
- '/oracle/agent/agent13.4'
дает (сокращенно)
msg: The name of LOC /oracle/19.0.0 is OraDB19Home1
msg: The name of LOC /oracle/agent/agent13.4 is OraHome1
Example of a complete playbook for testing
shell> cat pb.yml
- hosts: localhost
vars:
inv_xml: "{{ lookup('file', 'inventory.xml') }}"
inv_yml: "{{ inv_xml|ansible.utils.from_xml }}"
loc_name: "{{ inv_yml.INVENTORY.HOME_LIST.HOME|
items2dict(key_name='@LOC',
value_name='@NAME') }}"
loc: '/oracle/19.0.0'
name_of_loc: "{{ loc_name[loc] }}"
tasks:
- debug:
var: inv_xml
- debug:
var: inv_yml
- debug:
var: loc_name
- debug:
var: name_of_loc
- debug:
msg: "The name of LOC {{ item }} is {{ loc_name[item] }}"
loop:
- '/oracle/19.0.0'
- '/oracle/agent/agent13.4'
Example of the project
shell> tree .
.
├── ansible.cfg
├── hosts
├── inventory.xml
└── pb.yml
0 directories, 4 files
shell> cat ansible.cfg
[defaults]
gathering = explicit
collections_path = $HOME/.local/lib/python3.9/site-packages/
inventory = $PWD/hosts
roles_path = $PWD/roles
remote_tmp = ~/.ansible/tmp
retry_files_enabled = false
stdout_callback = yaml
shell> cat hosts
localhost
Q: "Дайте альтернативу ansible.utils"
О: Установите jc и используйте его в пайпе. Объявление ниже расширяется до того же YAML, что и раньше.
inv_yml: "{{ lookup('pipe', 'cat inventory.xml | jc --xml') }}"
Q: "Используя возможное регулярное выражение?"
A: Сначала выберите строку
inv_xml: "{{ lookup('file', 'inventory.xml') }}"
loc: '/oracle/19.0.0'
home_loc_regex: '^\s*<HOME .*? LOC = "{{ loc }}" .*$'
home: "{{ inv_xml.splitlines()|
select('regex', home_loc_regex)|
first|
trim }}"
дает
home: <HOME NAME = "OraDB19Home1" LOC = "/oracle/19.0.0" TYPE = "O" IDX = "2"/>
Разобрать атрибуты
home_dict: "{{ dict(home[6:-2]|
replace('\"', '')|
split(' ')|
map('split', '=')) }}"
дает
home_dict:
IDX: '2'
LOC: /oracle/19.0.0
NAME: OraDB19Home1
TYPE: O
В: «Нет фильтра с названием «разделить»»
О: Фильтр сплит доступен с 2.11. Для более ранних версий доступен только метод «.split». В этом случае используйте Jinja и создайте структуру YAML. Объявления ниже дают тот же словарь home_dict, что и раньше.
home_dict_str: |
{% for i in home[6:-2].split(' ') %}
{% set arr = i.split('=') %}
{{ arr.0 }}: {{ arr.1 }}
{% endfor %}
home_dict: "{{ home_dict_str|from_yaml }}"
Большое спасибо. Я смотрел на них, чтобы импровизировать, stackoverflow.com/questions/72022134/… и следующее, на что вы ответили в другой теме, потеряло ссылку для этого. - set_fact: MQSFILEPARSED: "{{ lookup('file', FILE).splitlines()| select('match', '^(.*) LOC=(.*)$')| map('regex_replace', my_regex , my_replace)| список }}"
Получение ansible.utils оказалось сложной задачей. Цените, если вы можете дать альтернативу, используя возможное регулярное выражение? Еще раз спасибо.
Вместо этого используйте jc. Я добавил пример. Что сложного в ansible.utils?
Я добавил опцию «regex».
Большое спасибо еще раз! Администраторы нашего сервера не хотят добавлять эти утилиты. Вот где я разрабатываю playbooks. В конечном итоге они попадут в Башню. И в Tower env эти утилиты не установлены. Когда я связался с администратором башни, он сказал, что у меня должна быть пользовательская оболочка exec. Не был уверен, сколько из этого я хотел баловаться с ограниченным временем и т. д. Всегда ценю вашу помощь. Я набираю пива для вас здесь, в Хьюстоне :)
Полезно знать :) Посмотрите, доступен ли вам Community.General . Здесь добавляются и обновляются новые материалы. Например, вы можете использовать jc также в качестве фильтра.
Давайте продолжим обсуждение в чате.
Спасибо! Да, в настоящее время я использую что-то похожее в существующем сценарии оболочки, который я пытаюсь написать как доступную книгу. Поэтому искал что-то доступное решение.