yqを使わずにsedでyamlファイルの編集する

はじめに

yq使えばいいじゃん、なのですが、環境によってインストールしたくない場合があります。でもyamlファイルの中身を書き換えたい。そんな時にsedを使えば解決できます。

今回は例としてハッシュ(キー: バリュー)のみの単純なデータ構造で構成するファイルを使用して説明していきたいと思います。尚、yamlファイルはハッシュのみならず、配列やネスト(入れ子)の構造も扱えます。そのような構造が入り混じっていても適宜指定する方法があるので、本記事をベースに応用していただけますと幸いです。

yamlファイルを作成する

👉手順1

  • yamlファイルを作成
    • ファイル名:test.yaml
    • ファイルの中身
key1: value1
key2: value2
key3: value3

yqコマンドでファイルの中身を書き換える方法

まず、従来のyqでファイルの中身を書き換える方法について確認します。

$はコマンド部分を表したものです。実際には入力しないでください。$の無い部分は出力結果を表します。

yqコマンドでファイルの中身を書き換える

下記がコマンドの構文になります。

$ yq '[.キー=バリュー]' [ファイルパス] 

👉手順2

  • では、key1の値をChanged1に変更してみます。
$ yq '.key1 = "Changed1"' test.yaml
key1: Changed1
key2: value2
key3: value3
  • key1の値が書き換わったものが出力されました。しかし、ファイルに出力していないので実際のファイルは書き変わっていません。catコマンドでファイルの中身を確認できます。
$ cat test.yaml 
key1: value1
key2: value2
key3: value3

yqコマンドで得た値をファイルとして出力する。

下記のように入力します。

$ yq '[.キー=バリュー]' [ファイルパス] > [出力ファイルパス]

👉手順3

  • ではkey1の値をChanged1に変更し、変更したものを「changed.yaml」としてファイルに出力します。
$ yq '.key1 = "Changed1"' test.yaml > changed.yaml
  • 「changed.yaml」の中身をcatコマンドで確認
$ cat changed.yaml
key1: Changed1
key2: value2
key3: value3

書き変わっているのが確認できます。

続いては上記yqコマンドで行ったyamlファイルの書き換え、ファイル出力をsedコマンドを使って行う方法について説明します。先程の手順で作成された「changed.yaml」を削除してから次の手順に移ります。

$ rm changed.yaml

sedコマンドでファイルの中身を書き換える方法

先程説明したyqコマンドで行ったことをsedで同じように行います。

sedコマンドでファイルの中身を書き換える

下記がsedで値を書き換える際の基本的なコマンドの構文になります。

$ sed -e "s/[書き換え対象の文字列]/[書き換える値]/g" [書き換えるファイルのパス]

👉手順4

  • では、key1の値をChanged1に変更してみます。
$ sed -e "s/key1: value1/key1: Changed1/g" test.yaml
key1: Changed1
key2: value2
key3: value3
  • key1の値が書き換わったものが出力されました。しかしyqと同様に、ファイルに出力していないので実際のファイルは書き変わっていません。catコマンドでファイルの中身を確認できます。
$ cat test.yaml 
key1: value1
key2: value2
key3: value3

sedコマンドで得た値をファイルとして出力する

先程と同様に下記のように入力します。

$ sed -e "s/[書き換え対象の文字列]/[書き換える値]/g" [書き換えるファイルのパス] > [出力ファイルパス]

👉手順5

  • ではkey1: value1key1: Changed1に変更し、変更したものを「changed.yaml」としてファイルに出力します。
$ sed -e "s/key1: value1/keyi: changei/g" test.yaml > changed.yaml
  • 「changed.yaml」の中身をcatコマンドで確認
$ cat changed.yaml
key1: Changed1
key2: value2
key3: value3

書き変わっているのが確認できます。

バリューの値が固定値では無い時は正規表現で書き換える!

前のsed例ではバリューの値が固定では無い時、分からない時は対応できません。yqの場合は「キー=~~」という形で記述できたので、同じような事をするためには、正規表現を使う事で解決できます。

下記が正規表現を使ってバリューの値が固定値では無い場合でも対応できるコマンドの構文になります。

$ sed -e "s/^[書き換え対象の文字列]:.*/[書き換えるキー]: [書き換えるバリュー]/g" [書き換えるファイルのパス] > [出力ファイルパス]

👉手順6

  • ではkey1の値をChanged1に変更し、変更したものを「changed.yaml」としてファイルに出力します。
$ sed -e "s/^key1:.*/key1: Changed1/g" test.yaml > changed.yaml
  • 「changed.yaml」の中身をcatコマンドで確認
$ cat changed.yaml
key1: Changed1
key2: value2
key3: value3

書き変わっているのがわかります。

因みにsed-iオプションを使えばファイルを上書きすることもできます。その場合は下記コマンドになります。

$ sed -i -e "s/^key1:.*/key1: Changed1/g" test.yaml

-eコマンドはexpressionの略で続くものがスクリプト処理であることを明示的に表しています。s/○○/●●/gスクリプトにあたります。

正規表現^」、「.」、「*」について

使用した正規表現についてひとつずつ説明していきます。

  • ^正規表現で「行頭」を表します。今回の例では、ネストされていないyamlファイルを用いましたので、キーは行頭から始まります。これを使わないと例えば「config_key1」、「hoge-key1」などの「key1」が含まれる文字列全てが対象となって思い通りの挙動にならない可能性があります。
  • .正規表現で「任意の文字列」を表します。今回の例の場合は空白(スペース)を表します。今回の例では:の次にスペースを挟むのがyamlの形式ですので、空白文字を判定する必要があります。
  • *正規表現で「直前パターンの繰り返し」を表します今回の場合は文字列の繰り返しを表し、「v a l u e 1」を抽出します。

→合わせると「(行頭)key1:(空白)(文字列の繰り返し)」を「key1: Changed1」に書き換えるという意味になります。

終わりに

最後まで読んでいただきありがとうございました。yqが便利でyamlコマンドを使ってシェルスクリプトガリガリ書いていたのですが、yqをインストールできない要件の環境で実行することになり、やむなくsedに変更する作業が発生しました。なかなかピンポイントで同じことをやっている人がいなかったので投稿に至りました。