Bashでコマンドライン引数の次の引数にアクセスするには?

Bashでコマンドライン引数の次の引数にアクセスするには?

以下があるとしましょう。

for i in $@; do
    echo ${i+1}
done

シェルで実行すると Why ${i+1} does not work?$ test.sh 3 5 8 4が出力されます。1 1 1 1コマンドライン引数リストから次の引数にアクセスしようとしています。

答え1

シェルの各文字は特別な意味を持つことができます。

このコードは${i+1}「i+1」を意味しません。
これが何を意味するのかを理解するには、次のコマンドを実行します。

LESS=+/'\{parameter\:\+word\}' man bash

そして読んでください:

${parameter:+word}
代替値を使用してください。引数が空であるか設定されていない場合は何も置き換えられず、そうでない場合は単語の拡張が置き換えられます。

少し上:

コロンを省略すると、設定されていないパラメータのみがテストされます。

$iループが値を設定するため、for i in $@;「代替値」が置き換えられて1印刷されます。

パラメーター値を1ずつ増やすには、次のようにします。

for    i
do     echo "$((i+1))"
done

必要ありませんin "$@"(そしてすべての拡張子を引用するのに慣れています)。

$ ./test.sh 3 5 8 4
4
6
9
5

続く主張。

しかし、これは「次の主張」でもありません。重要な問題は、パラメータのインデックスではなくパラメータの値を使用するループにあります。i各パラメータの値ではなくパラメータのインデックスを繰り返す必要があります。iそれは次のとおりです。

for (( i=1; i<=$#; i++)); do
    echo "${i}"
done

これにより、次のインデックスが印刷されます。

$ ./test.sh 3 5 8 4
1
2
3
4

間接的な

$ipositionのパラメータにどのようにアクセスしますか? :間接使用:

for (( i=1; i<=$#; i++)); do
    echo "${!i}"
done

簡単な!追加が見えますか?

これで、次のように実行されます。

$  ./test.sh  3 5 8 4
3
5
8
4

最後の解決策。

現在のパラメータと次のパラメータを印刷するには、次のコマンドを使用します。

for (( i=1; i<=$#; i++)); do
    j=$((i+1))
    echo "${!i} ${!j}"
done

いいえ、変数の値を計算するよりも簡単な方法はありません$j


$ ./test.sh 3 5 8 4
3 5
5 8
8 4
4 

これはテキストにも当てはまります。

$ ./test.sh sa jwe yqs ldfgt
sa jwe
jwe yqs
yqs ldfgt
ldfgt 

答え2

あなたのサンプルコードでは、iはインデックスではなく値です。
変数の値を変数として使用するには、感嘆符を使用する必要があります。
他の変数を定義しないと(i + 1)を操作できません。たぶん誰かが最適化のヒントを与えるかもしれません。

check () {
  for i in $(seq $#); do
    let j=i+1
    echo "$i: i=${!i} i+1=${!j}"
  done
}

check a b c

1: i=a i+1=b
2: i=b i+1=c
3: i=c i+1=

答え3

まず${i+1}、パラメータ拡張モードです。つまり、パラメータがi設定されていないかnullの場合の拡張に置き換えられ、1結果はです1。したがって、出力にはすべて1が表示されます。

パラメーター拡張ではなく算術演算子を使用する必要があります。

たとえば、

% check () { for i in "$@"; do echo $((i+1)); done ;} 

% check 2 4 5 6
3
5
6
7

答え4

拡張user79743の上記から回答しました。

--mode deleteまたは、同じ値を取るパラメータが欲しいとします--mode list

${!i} == "--mode"、私たちが読みたい値次のようなインデックス(jまたはi+1)を指定し、後で使用するためにアーカイブします。次のループ反復では、i+12回目のチェック(j前のループ、i現在のループ)を実行することを検討してください。

私はそれが可変であることを知っていたので、私たちはそれを1ずつ増やすことiができます。i+2

一般に、反復中に値を変更することは賢明ではないと言いたいと思います。この方法は私にとって本当に効果的です。私はこれを行うためのいくつかの(より良い)方法があると確信しています。

増加しませんi。一部のインデックスは複数回確認されます。

# $ ./test.sh --mode delete 3 5 8 4
# [1]: --mode [2]: delete
# [2]: delete # <-- index [2] is inspected twice
# [3]: 3
# [4]: 5
# [5]: 8
# [6]: 4
for (( i=1; i<=$#; i++)); do
  if [[ ${!i} == "--mode" ]]; then
    j=$((i+1))
    MODE=${!j} # retain for later
    echo "[$i]: ${!i} [$j]: ${!j}"
  else
    echo "[$i]: ${!i}"
  fi
done

増加すると、i各インデックスは一度だけチェックされます。

# $ ./test.sh --mode delete 3 5 8 4
# [1]: --mode [2]: delete
# [3]: 3
# [4]: 5
# [5]: 8
# [6]: 4
for (( i=1; i<=$#; i++)); do
  if [[ ${!i} == "--mode" ]]; then
    j=$((i+1))
    MODE=${!j} # retain for later
    echo "[$i]: ${!i} [$j]: ${!j}"
    i=$i+1 # <-- incrementing the index
  else
    echo "[$i]: ${!i}"
  fi
done

関連情報