web-dev-qa-db-ja.com

シフトを呼び出した後、引数のシフトを解除します

私はこのシナリオを持っています

first_arg="$1";

if foo; then
    shift 1;
    node foo.js "$@"

Elif bar; then

   shift 1;
    node bar.js "$@"

Elif baz; then

   shift 1;
   node baz.js "$@"

else

   node default.js "$@"

fi

上記をこれに変えたい:

first_arg="$1";
shift 1;

if foo; then

    node foo.js "$@"

Elif bar; then

    node bar.js "$@"

Elif baz; then

   node baz.js "$@"

else

   unshift 1;
   node default.js "$@"

fi

しかし、私がちょうど作ったシフトなしのようなオペレーターがいるかどうかはわかりません。回避策の1つは次のとおりです。

node default.js "$first_arg" "$@"

しかし、それを試したとき、私は奇妙な行動を得ました。

6
Alexander Mills

引数を配列に保存できます:

args=( "$@"  )  # use double quotes
shift 1

if foo; then
  node foo.js "$@"
Elif bar; then
  node bar.js "$@"
Elif baz; then
  node baz.js "$@"
else
  node default.js "${args[@]}"
fi
6
jesse_b

そもそもshift 1を使用する必要はありません。位置引数を使用し、それらのインデックスをスライスして引数を渡します。

first_arg="$1"

これを行うと、残りの引数は"${@:2}"としてアクセスできます。表記は、位置引数2からリストの最後までを表す方法です。

あなたの例の構成を使用すると、

node foo.js "${@:2}"

そして最後のelse部分は

node default.js "$1" "${@:2}"

これは、位置引数のシフトが行われないため、"$@"を実行するのと同じです。

10
Inian

あなたが試したこと:

first_arg=$1
shift

# ...later...

else
    node default.js "$first_arg" "$@"
fi

これは、少なくとも1つのコマンドライン引数がある場合、最初のバリアントと同じになります。

コマンドライン引数がない場合でも、"$first_arg"は空の文字列、つまり引数になりますが、"$@"は空の文字列も生成しません。

Nodeアプリケーションがコマンドラインで空の引数を受け入れる場合、2つのコードバリアントでアプリケーションの動作が異なる可能性があります。

コマンドライン引数なしでスクリプトを呼び出すことが有効な場合、次のようにすることができます

node default.js ${first_arg:+"$first_arg"} "$@"

ここで、${first_arg:+"$first_arg"}は、first_argが空または未設定の場合は何にも展開されませんが、"$first_arg"が空でない文字列に設定されている場合はfirst_argに展開されます。または、未設定または空の変数に対して明示的なエラーを発生させたい場合:

node default.js "${first_arg:?Error, no command line arguments}" "$@"

代替案には、$@のコピーをbash配列として作成することが含まれます Jesse_bが彼の回答で示しているように

$first_arg$@に戻す

set -- "$first_arg" "$@"`

コマンドライン引数がない場合、これは$1$@として空の引数を含むため、機能しません。

set -- ${first_arg:+"$first_arg"} "$@"`

$first_argが空の場合、または変数が存在しない場合は、何も「シフト解除」します。


シフトはシフト1と同じであり、単一のステートメントをで終了する必要がないことに注意してください。同じ行に別のステートメントが続いていない限り(newlineは;と同じようにコマンド終了文字です)。

7
Kusalananda