N 個のパラメータを取得するスクリプトがあります。最初にそれらを解析し (特定の値を抽出しますX
)、次にその値を使用して別のプログラムを呼び出します。
function main() {
parse "$@"
run "$@"
}
main "$@"
args リストの先頭にオプションのパラメータ (実行している Python バージョンを設定するパラメータ) を追加したいと思います。そこで、これを解析関数に追加しました。
if [ "$1" = '2' ] || [ "$1" = '3' ]; then version=$1 && shift; else version=2; fi
しかし、解析が終了した後、shift
実行関数に影響を与えないために行き詰まってしまいます。最初の値の値を再度確認せずにこれを行うにはどうすればよいですか(そうすると、解析関数を持つ目的全体が台無しになります)
答え1
各シェル関数のスコープ(およびスクリプトのトップレベルコードのスコープ)には、独自の位置パラメータ、そして自分自身にしか直接アクセスできません。最もクリーンな解決策は、関心のある位置パラメータの値をの配列その後、複数の関数スコープでその配列を読み取ったり、変更したりできるようになります。
たとえば、スクリプトの先頭近くに次のコードを配置することができます。
declare -a args=("$@")
- 配列には好きな名前を付けることができます。 という名前にする必要はありません
args
。 declare -a
必要に応じて、を省略することもできます。- 必ずしも冒頭に現れる必要はありません。走るにアクセスするコードが
args
実行される前。 を使用するシェル関数の定義の下にも配置できますargs
。わかりやすくするために、先頭近くに配置することを推奨します。
その後、複数の関数から配列を操作できますargs
。関数に配列を渡す必要はありません。関数はすでに配列にアクセスできるようになります。シェル関数内のコードが配列の内容を変更してargs
戻ると、呼び出し元のコードでその変更を監視できます。
Bash を含む Bourne スタイルのシェルの位置パラメータでは、1 ベースのインデックスが使用されます。(これは$0
、プログラム名に展開される は技術的には位置パラメータではなく、関数スコープ内で変化しないためです。) ただし、Bash の配列では 0 ベースのインデックスが使用されます。したがって、 の後では、args=("$@")
はと$1
一致し${args[0]}
、は と$2
一致し${args[1]}
、$3
は${args[2]}
と一致し、以下同様に一致します。は、予想どおりに$@
一致し続けます。${args[@]}
読みやすくするために、引用符なしでそのように記述しました。もちろん、args
位置パラメータを含む展開をほぼ常に二重引用符で囲むのと同じように、配列を含む展開をほぼ常に二重引用符で囲む必要があります。
このアプローチを採用することに決めた場合は、次の操作の代わりに、
shift
次のように書きます:
args=("${args[@]:1}")
Bashの配列を初めて使う場合は、以下をご覧ください。Bashリファレンスマニュアルの関連部分インタラクティブに実験してみるのも良いでしょう。例えば:
ek@Cord:~$ args=('foo bar' 'baz quux' 'ham spam')
ek@Cord:~$ printf '[%s]\n' "${args[@]}"
[foo bar]
[baz quux]
[ham spam]
ek@Cord:~$ printf '[%s]\n' "${args[@]:1}"
[baz quux]
[ham spam]
対応するコードは
if [ "$1" = 2 ] || [ "$1" = 3 ]; then
version="$1"
shift
else
version=2
fi
だろう:
if [ "${args[0]}" = 2 ] || [ "${args[0]}" = 3 ]; then
version="${args[0]}"
args=("${args[@]:1}")
else
version=2
fi
配列を使用すると構文的にはより面倒になりますが、より柔軟性も高まります。
一方、スクリプトのコードの大部分は関数run
とその呼び出し元に整理されているようなので、特別なコマンドライン引数を解析するという代替案を検討してもよいかもしれません。前にrun
をシェル関数の外部で呼び出し、その後、run "$@"
既に行っているように呼び出します。
プログラミング言語の中には、ほとんどすべてを小さくて自己完結的な関数にまとめるという強い倫理観が文化に根付いているものがあります。Bash はそのような言語ではありません。シェル関数から複雑なデータを返す方法が限られていることがその理由の 1 つです。シェル関数を書くことを恐れてはいけませんし、小さなシェル関数を大量に書くこともいとわないべきです。しかし、スクリプトに最適な形式が別のものであることが判明しても心配する必要はないと思います。
さらに詳しい情報や、プロセス置換の出力をソースとする奇妙なアプローチを含むいくつかの代替案については、以下を参照してください。ジルの答えに関数呼び出し位置パラメータ。