Хорошо помнить эти простые правила, и они применяются как к параметрам, так и к возвращаемым типам ...
Есть время и место для каждого, поэтому убедитесь, что вы узнаете их. Локальные переменные, как вы показали здесь, просто таковы, что они ограничены временем, когда они локально живы в области функций. В вашем примере с возвращаемым типом int*
и возвратом &i
было бы одинаково некорректно. Вам было бы лучше в этом случае сделать это ...
void func1(int& oValue)
{
oValue = 1;
}
Это приведет к прямому изменению значения вашего переданного параметра. В то время как этот код ...
void func1(int oValue)
{
oValue = 1;
}
не будет. Он просто изменит значение oValue
локально на вызов функции. Причина этого заключается в том, что вы фактически меняете только «локальную» копию oValue
, а не oValue
.
Если вы можете установить новые зависимости и планируете работать с большим количеством файлов yaml, yq
- это оболочка для jq, которая может обрабатывать yaml. Это позволило бы безопасный (не grep) способ доступа к вложенным значениям yaml.
Использование выглядело бы примерно так: MY_VALUE=$(yq '.myValue.nested.value' < config-file.yaml)
В качестве альтернативы, Как я могу проанализировать файл YAML из сценария оболочки Linux? имеет парсер только для bash, который вы можете использовать для получения ваша ценность.
Поскольку другие комментируют, рекомендуется использовать yq
(вместе с jq
), если доступно.
Затем попробуйте следующее:
value=$(yq -r 'recurse | select(.name? == "CALICO_IPV4POOL_CIDR") | .value' "calico.yaml")
echo "$value"
Вывод:
192.168.0.0/16
Правильный способ сделать это - использовать язык сценариев и библиотеку синтаксического анализа YAML для извлечения интересующего вас поля.
Вот пример того, как это сделать в Python. Если бы вы делали это по-настоящему, вы бы, вероятно, разбили его на несколько функций и получили бы лучшие отчеты об ошибках. Это буквально просто для иллюстрации некоторых трудностей, вызванных форматом calico.yaml
, который объединяет несколько документов YAML, а не один. Вам также нужно перебрать некоторые из внутренних списков в документе, чтобы извлечь интересующее вас поле.
#!/usr/bin/env python3
import yaml
def foo():
with open('/tmp/calico.yaml', 'r') as fil:
docs = yaml.safe_load_all(fil)
doc = None
for candidate in docs:
if candidate["kind"] == "DaemonSet":
doc = candidate
break
else:
raise ValueError("no YAML document of kind DaemonSet")
l1 = doc["spec"]
l2 = l1["template"]
l3 = l2["spec"]
l4 = l3["containers"]
for containers_item in l4:
l5 = containers_item["env"]
env = l5
for entry in env:
if entry["name"] == "CALICO_IPV4POOL_CIDR":
return entry["value"]
raise ValueError("no CALICO_IPV4POOL_CIDR entry")
print(foo())
Однако иногда вам нужно решение прямо сейчас , и сценарии оболочки очень хороши в этом.
Если вы работаете с конечной точкой API, то YAML, как правило, будет хорошо напечатан, поэтому вы можете с легкостью извлекать текст способами, которые не будут работать с произвольным YAML.
Что-то вроде следующего должно быть довольно устойчивым:
cat </tmp/calico.yaml | grep -A1 CALICO_IPV4POOL_CIDR | grep value: | cut -d: -f2 | tr -d ' "'
Хотя в конце стоит проверить с помощью регулярного выражения, что извлеченное значение действительно является действительной нотацией CIDR IPv4.
Ключевым моментом здесь является grep -A1 CALICO_IPV4POOL_CIDR
.
Упомянутый вами двухэлементный словарь (показанный ниже) всегда будет отображаться как один фрагмент, так как это поддерево документа YAML.
- name: CALICO_IPV4POOL_CIDR
value: "192.168.0.0/16"
Ключи в calico.yaml
не сортируются в алфавитном порядке в целом, но в конструкциях {"name": <something>, "value": <something else>}
, name
последовательно появляется до value
.
У вас есть две проблемы:
Я догадался, что вам нужен документ YAML типа 'DaemonSet' из прочтения ответа Грегори Нисбетта.
Я постараюсь использовать только те инструменты, которые, вероятно, уже установлены в вашей системе, потому что вы упомянули, что хотите сделать это в скрипте Bash. Я предполагаю, что у вас есть JQ, потому что без него очень сложно сделать в Bash!
Для библиотеки YAML я склонен использовать Ruby для этого, потому что:
предложил использовать yq , но это не очень поможет в этом случае, потому что вам все еще нужен инструмент, который может извлечь документ YAML.
После извлечения документа я собираюсь снова использовать Ruby для сохранения файла в формате JSON. Тогда мы можем использовать JQ.
Извлечение документа YAML
Чтобы получить документ YAML с использованием Ruby и сохранить его как JSON:
url=...
curl -s $url | \
ruby -ryaml -rjson -e \
"puts YAML.load_stream(ARGF.read)
.select{|doc| doc['kind']=='DaemonSet'}[0].to_json" \
| jq . > calico.json
Дальнейшее объяснение:
Я передаю этот ответ через jq .
, чтобы он был отформатирован для удобства чтения, но этот шаг не является действительно необходимым. Я мог бы сделать то же самое в Ruby, но я предполагаю, что вы хотите, чтобы код Ruby был минимальным.
Выбор нужной клавиши
Чтобы выбрать нужную клавишу, можно использовать следующий JQ-запрос:
jq -r \
'.spec.template.spec.containers[].env[] | select(.name=="CALICO_IPV4POOL_CIDR") | .value' \
calico.json
Дальнейшее объяснение:
[ 1140]spec.template.spec.containers[].env[]
выполняет итерации для всех контейнеров и для всех envs внутри них Собирая все вместе:
#!/usr/bin/env bash
url='https://docs.projectcalico.org/v3.3/getting-started/kubernetes/installation/hosted/kubernetes-datastore/calico-networking/1.7/calico.yaml'
curl -s $url | \
ruby -ryaml -rjson -e \
"puts YAML.load_stream(ARGF.read)
.select{|doc| doc['kind']=='DaemonSet'}[0].to_json" \
| jq . > calico.json
jq -r \
'.spec.template.spec.containers[].env[] | select(.name=="CALICO_IPV4POOL_CIDR") | .value' \
calico.json
Тестирование:
▶ bash test.sh
192.168.0.0/16