YAMLファイルには複数の構成があり、Bashスクリプトを使用していくつかのパラメーターを変更する必要があります。可能ですか?外部依存関係の使用を避けたい。
私のYAMLは次のとおりです
%YAML 1.2
---
name: mic
components:
- name: Mic
parameters:
period_count: 4
alsa_device_name: "pulse"
---
name: speaker
components:
- name: Speaker
parameters:
period_duration_ms: 20
period_count: 4
alsa_device_name: "pulse"
私が提供したように動作したい場合は、私の設定で次のように--mic logitec --speaker hk34
変更する必要があります。alsa_device_name
mic
speaker
%YAML 1.2
---
name: mic
components:
- name: Mic
parameters:
period_count: 4
alsa_device_name: "logitec"
---
name: speaker
components:
- name: Speaker
parameters:
period_duration_ms: 20
period_count: 4
alsa_device_name: "hk34"
Bashだけを使用してこれを実行できますか?可能であればどのように達成できますか?今はPythonスクリプトを使用していますが、これを行うとhaveへの追加の依存関係が追加されるので、python3
これを避けたいと思います。
答え1
まず、明確に定義された構文を持つYAMLなどの言語を解析するために行ベースのツールを使用することはお勧めできません。本番では使用しないでください!いいえ。
コマンドラインを介してYAMLを解析するためのいくつかの構文認識ツールがあります。Pythonyq
そして行くyq
。これは、標準行ベースのツールとして理解されていないアンカーやブロックリテラルなどのYAMLの構造をサポートします。
上記のワンタイム処理の場合は、awk
次のようなものを使用できます。
BEGIN {
map["name: mic"] = "\"logitec\""
map["name: speaker"] = "\"hk34\""
}
match($0, "name: mic") || match($0, "name: speaker") {
key = substr($0, RSTART, RLENGTH)
}
/alsa_device_name/ {
sub(/:.*/, ": " map[key])
}
{ print }
awk
上記の内容をスクリプト(.awk
)に入れて、awk -f script.awk yaml
コマンドラインの一部として実行できます。コマンドラインで値を次のように定義することもできます。
awk -v mic='"logitec"' -v speaker='"hk34"' -f script.awk yaml
ブロックのパラメータを次BEGIN
のように処理します。
BEGIN {
map["name: mic"] = mic
map["name: speaker"] = speaker
}
また、入力は有効なYAMLファイルではなく、ヘッダー行のため、%YAML 1.2
ほとんどの標準YAMLパーサーは入力構文にエラーを発生させます。
答え2
yq
この回答を書く前に、他の回答を受け入れるのを待っていました。https://kislyuk.github.io/yq/
#!/bin/bash
unset mic
unset speaker
while getopts m:s: opt; do
case $opt in
m)
mic=$OPTARG
;;
s)
speaker=$OPTARG
;;
*)
echo 'invalid option' >&2
exit 1
esac
done
shift "$(( OPTIND - 1 ))"
yaml_update () {
key=${1,,} # lower-case, e.g. "mic"
Key=${key^?} # title-case, e.g. "Mic"
value=$2
yq -Y --arg key "$key" --arg Key "$Key" --arg value "$value" '
(select(.name == $key).components[] |
select(.name == $Key).parameters.alsa_device_name) |= $value'
}
if [ "${mic+set}" = "set" ]; then
yaml_update mic "$mic"
else
cat -
fi |
if [ "${speaker+set}" = "set" ]; then
yaml_update speaker "$speaker"
else
cat -
fi
スクリプト内のほとんどのコードは、与えられたコマンドラインオプションに関連するコマンドラインの解析とロジックです。これは、便利なオプションセットでコマンドラインでソリューションを使用できる必要があるという質問の要件、または少なくとも提案によるものです。実際のコードは何かをしなさいyaml_update
関数に配置され、3行のコードで構成されています(yq
コマンド、1行のコードが長すぎて3行しかありません)。
スクリプトは次のように使用されます。
./script -m logitec -s hk34 <file.yaml >file-new.yaml
2つのオプションのコマンドラインオプションが必要です-m
(-s
質問に提案されている長いオプションは標準ではなく、組み込みではサポートさgetopts
れていませんbash
)マイクそして/またはスピーカーそれぞれ Alsa デバイス名です。
YAML 文書は標準入力として読み取られ、結果文書は標準出力に書き込まれます。
更新は、yq
キーに基づいて正しい最上位オブジェクトを選択する式を使用name
し、次を使用してcomponents
配列から正しい配列要素を選択することによって行われます。それ name
キー。次に、alsa_device_name
選択した要素キーparameters
の下の値を更新します。
便宜上、yq
呼び出しはシェル関数に移動されました(非常に似た呼び出しを2回実行できるため、yq
これは合理的に見えます)。
上記のように与えられた文書を変更すると、出力は次のようになります。
name: mic
components:
- name: Mic
parameters:
period_count: 4
alsa_device_name: "logitec"
---
name: speaker
components:
- name: Speaker
parameters:
period_duration_ms: 20
period_count: 4
alsa_device_name: "hk34"