はじめに
シェルスクリプトの alias
はコマンドに対して別名をつけたり、標準で追加するオプションを定義したりするために、主に(シェルスクリプトではなく)対話シェルで使う機能です。しかしその機能は単語を置き換えるだけという単純な機能であるため、メタプログラミングやシェル言語のハックに利用することができます。これを利用して変数を使わずにコマンドの引数を変更するテクニックを思いついたので紹介します。
コードと説明
# bash の場合にシェルスクリプトでエイリアスを有効にする
[ $BASH_VERSION ] && shopt -s expand_aliases
cmd() { echo "$#" : "$@"; }
alias cmd="cmd "
alias args="a b c"
cmd args # cmd a b c => 3 : a b c
alias args="'a b c'"
cmd args # cmd 'a b c' => 1 : a b c
このコードで珍しいのは、おそらく alias cmd="cmd "
の末尾にあるスペースでしょう。本来この機能は後続の単語をエイリアス展開する時に使います。例えば nohup
コマンドを使うときなどに使用します。nohup
コマンドはコマンドを実行したまま端末をログアウトする時に使うコマンドで以下のような形で使います。
$ nohup backup.sh &
一般的にエイリアスは最初の単語、つまり nohup
しかエイリアス展開の対象になりません。もし後続の単語、つまり backup.sh
もエイリアス展開の対象にしたい場合は alias nohup="nohup "
とエイリアスを定義すれば可能になります。本来はこのように後続の「コマンド」に対してエイリアス展開を行うのですが、結局のところシェルにとってコマンド名と引数に違いはなくどちらも単なる文字列です。別にコマンドでなくとも展開することができます。
エイリアス展開は単なる文字列として展開を行います。したがって次のようなコードは正しく動作します。
alias tr="tr "
alias "%file%"='< "$file"'
file=/etc/hosts
tr %file% a-z A-Z
エイリアスを利用すると変数を使うだけではできないことができてしまうのです。嫌われがちの eval
も使用していません。もっともやっていることは eval
と大差ありませんが。
さいごに
このようなテクニック(メタプログラミング)は一般的なシェルスクリプトで使うようなものではなく、使い方を間違えるとトラブルの原因になり得ますが、時としてシェルスクリプトの限界を超えるようなことを可能にできたりします。今のところ便利な使い方は思いついていませんが、なにか変わったことができそうだと予感しています。