🐈

shellscript の '$@' は、とても便利だった

に公開

概要

shell script には、 全コマンドライン引数を扱う $@ という値が用意されています。

先日、 $@ のユースケースを学ぶ機会があり、その効果に驚きました。

学んだユースケースと共に、 $@ の効果を少しでも伝えられればと思います。

$@ とは

シェルスクリプトにて使用できる、全コマンドライン引数を格納した変数です。

$@ を参照することで、全コマンドライン引数をまとめて扱うことが出来ます。

at_sample.sh
echo "$@"
$ bash at_sample.sh hoge fuga
hoge fuga

$ bash at_sample.sh foo bar hogera
foo bar hogera

ユースケース

shell script 内で疑似エイリアス

コマンドを短縮するためのエイリアスは便利ですが、シェルスクリプト内では展開されず、そのまま実行されるため「command not found」エラーになります。

$ alias ll
alias ll='ls -alF'

$ cat ll_sample.sh
ll

$ bash ll_sample.sh
ll_sample.sh: line 1: ll: command not found

設定にて、シェルスクリプト内でのエイリアス展開を有効に出来ますが、意図しない動作の原因となるリスクがあります。

$@ を使用することで、エイリアスと同じような挙動を実現できます。

以下は、postgresql へ接続する汎用コマンドの例です。

connect_psql.sh
#!/bin/bash

# 各種環境変数は設定済みという想定
function connect_psql(){
  PGPASSWORD=${PGPASSWD} psql --host ${HOST} --port ${PORT} --user ${USER} "$@"
}
sample.sh
#!/bin/bash
source connect_psql.sh ## 上記 connect_psql関数を読み込む

connect_psql -c 'select * from my_table;' ## select
connect_psql -q --csv -f 'sql/get_users.sql' ## 任意のオプションも、 `$@` にて全部渡すことが出来る

$@ で任意の引数を扱えるため、 psql の任意のオプションを渡すことが出来ます。

コンテナイメージにて、 CMD 実行前に初期化スクリプトを実行させる

CMD で指定したコマンドを実行する前に、任意の初期化処理を行う init.sh を割り込ませます。

Dockerfile
FROM any_image

COPY init.sh entrypoint.sh /usr/local/bin
COPY main.sh .

ENTRYPOINT [ "entrypoint.sh" ]
CMD [ "Bash", "main.sh" ]
entrypoint.sh
#!/bin/bash

set -e

init.sh

exec "$@"
init.sh
echo "insert init script here." | tee sample.txt

これにより、 CMD で指定したコマンドは、 ENTRYPOINT の値と併せて、以下のようなコマンドとなります。

entrypoint.sh Bash main.sh

entrypoint.sh では、最初に init.sh を実行し、続く引数を exec コマンドで評価します。

結果として、処理順は以下のようになります。

  1. entrypoint.sh
  2. init.sh
  3. Bash main.sh (CMD で設定したコマンド)

後は、 init.sh に、任意の初期化処理を実装するだけです。

開発側は、 entrypoint.sh の存在を意識することなく、 CMD を好きに上書きできます。

所感

$@ の存在自体は知っていましたが、こういった活用方法は思いつきませんでした。

単純にして、非常に強力な値だと感じました。

色々と使い道を探っていきたいと思います。

Discussion