🕌

シェルスクリプトのprintfで引数を使い回したい

2022/10/15に公開

やりたいこと

printf '%s %s' a

a a

のように表示したいです(実際に実行すると、これはa になります)。

なぜ、これをやりたいかと言うと、

  • 同じようなクエリを複数のテーブルに投げるシェルスクリプトが欲しい
    • この仕組み自体はループとprintf組み合わせればすぐ
  • クエリ内でテーブルの名前を複数回参照したい時がある
    • クエリ内での参照が一回の時も、二回・三回の時も対応できると嬉しい

場合があったためです。

# hoge.shの中で処理対象のテーブル毎にクエリを実行。%sの部分に処理対象のテーブルを入れたい
# どのテーブルに対するクエリかわかるように、クエリ結果にテーブル名を入れたい場合もある
./hoge.sh 'SELECT "%s", id FROM %s'

zsh

zsh builtinのprintfの場合は簡単で、何番目の引数か指定するフォーマット(%n)があります。

Normally, conversion specifications are applied to each argument in order but they can explicitly specify the nth argument is to be used by replacing ‘%’ by ‘%n’ and ‘*’ by ‘*n’. It is recommended that you do not mix references of this explicit style with the normal style and the handling of such mixed styles may be subject to future change.

それを利用することで、今回やりたい処理を行うことができます。

# zsh
printf '%1$s %1$s' a
a a

zshのprintfを使いたい場合

  1. printfのフォーマット内の%sの数を数える
  2. その数の個数だけ、フォーマットに入れたい文字列を引数に渡す

で対応できそうです。

フォーマット($fmt)内の%sを数えるのはgrep -o(マッチした部分を新たな行で表示)とwcコマンドで出来ます。

echo $fmt | grep -o '%s' | wc -l

同じ文字列を繰り返すには、yesとhead

yes "繰り返したい文字列" | head -n $(echo $fmt | grep -o '%s' | wc -l)

xargsでprintfで渡して完成です

yes "繰り返したい文字列" | head -n $(echo $fmt | grep -o '%s' | wc -l) | xargs printf $fmt
SELECT "繰り返したい文字列",id FROM 繰り返したい文字列

Discussion