シェル(Bash)の引数展開について、自分でも忘れがちなので記録を残しておこうと思います。
正解は「2」です。
(参考: BASH - パス名展開)
文字列として、first/here-*をシェルスクリプトに渡したい場合は、 引数をダブルコーテーションで囲うか、事前にset -fを実行します。
例えば、以下は、here-*が展開されるタイミングによって展開結果が変わる例です。
私が気になったのは、関数の実行、または変数への代入で展開が起こるのかという点です。
展開のタイミングについて、マニュアルに以下の記載がありました。
BASH - 展開
この文章からコマンドの行に含まれる単語をインタプリタ(bash)が識別した後に、 展開が行われることがわかります。
関数は、コマンドと同じように処理されるため、同様に展開が起こるはずです。
以下のシェルスクリプト(show-func-args.sh)で確認してみます。
では変数への代入はどうでしょうか?
しかし、secondディレクトリ内のファイルが表示されたことから、変数代入時には展開が起きないことがわかりました。
前置き
この文章では引数展開の例を記述しています。 前提として、カレントディレクトリに、以下のディレクトリとファイルがあるものとします。
first/here-is-first1.txt
first/here-is-first2.txt
second/here-is-second1.txt
second/here-is-second2.txt
second/here-is-second3.txt
また、この文章で用いたbashのバージョンは以下の通りです。
$ bash --version
GNU bash, version 3.2.39(1)-release (i486-pc-linux-gnu)
Copyright (C) 2007 Free Software Foundation, Inc.
引数の展開例
以下の様に引数を表示するシェルスクリプト(show-args.sh)を用意します。
#!/bin/bash
echo "引数の数 : $#"
echo "引数 : $@"
このスクリプトに引数 first/here-* を指定して実行すると、
結果として表示される引数の数は幾つになるでしょうか?
$ ./show-args.sh first/here-*
正解は「2」です。
引数の数 : 2
引数 : first/here-is-first1.txt first/here-is-first2.txt
これは、パターンとみなされる文字「*」がパス名展開された結果が、引数となるためです。(参考: BASH - パス名展開)
文字列として、first/here-*をシェルスクリプトに渡したい場合は、 引数をダブルコーテーションで囲うか、事前にset -fを実行します。
$ ./show-args.sh "first/here-*"
引数の数 : 1
引数 : first/here-*
$ set -f && ./show-args.sh first/here-*
引数の数 : 1
引数 : first/here-*
展開のタイミング
展開タイミングによっては展開結果が変わります。例えば、以下は、here-*が展開されるタイミングによって展開結果が変わる例です。
#!/bin/bash
cd first
echo "first : " $1
cd ../second
echo "second : " $1
./show-args2.sh "here-*"
first : here-is-first1.txt here-is-first2.txt
second : here-is-second1.txt here-is-second2.txt here-is-second3.txt
ところで、展開が起きるタイミングはいつでしょうか?私が気になったのは、関数の実行、または変数への代入で展開が起こるのかという点です。
展開のタイミングについて、マニュアルに以下の記載がありました。
BASH - 展開
展開はコマンドラインが単語へ分割された後に (コマンドライン上で) 行われます。
この文章からコマンドの行に含まれる単語をインタプリタ(bash)が識別した後に、 展開が行われることがわかります。
関数は、コマンドと同じように処理されるため、同様に展開が起こるはずです。
以下のシェルスクリプト(show-func-args.sh)で確認してみます。
#!/bin/bash
function showFirstArg {
echo "引数の数 : $#"
echo "引数 : $@"
}
cd first
showFirstArg here-*
cd ../second
showFirstArg here-*
$ ./show-func-args.sh
引数の数 : 2
引数 : here-is-first1.txt here-is-first2.txt
引数の数 : 3
引数 : here-is-second1.txt here-is-second2.txt here-is-second3.txt
関数の実行で、展開が起こることがわかりました。では変数への代入はどうでしょうか?
#!/bin/bash
cd first
VAR=here-*
cd ../second
echo $VAR
$ ./show-var.sh
here-is-second1.txt here-is-second2.txt here-is-second3.txt
変数への代入時に展開が起きているとしたら、firstディレクトリ内のファイルが表示されるはずです。しかし、secondディレクトリ内のファイルが表示されたことから、変数代入時には展開が起きないことがわかりました。
まとめ
- 展開によって、引数の数、値が変わる。
- 展開は、コマンドまたは関数が実行される直前に行われる。
- 変数への代入では、展開が起きない。