x=( $@ ) と x="$@" 割り当ての違い

x=( $@ ) と x="$@" 割り当ての違い
#!/bin/bash

if [ $# -gt 0 ]; then
    snum=( $@ ) 
    echo $snum
fi

./testscript.sh 1234 4568 The Output of echo command is only などのスクリプトを実行するときに、1234すべての位置パラメータの配列を構築していないと思いますか?

#!/bin/bash

if [ $# -gt 0 ]; then
    snum="$@" 
    echo $snum
fi

./testscript.sh 1234 4568 出力を実行すると、次のようになります。1234 4568

snum=( $@ )なぜ最初の位置パラメータのみが使用されるのか疑問に思います。

答え1

リストコンテキスト"$@"(二重引用符を含む)で使用して取得します。リスト個別に引用された位置パラメータ。

スカラーコンテキスト"$*"(二重引用符を含む)で使用して位置引数を連結します。単一文字列最初の文字$IFS(通常はスペース)を区切り文字として使用します。

$@引用符なしで(最初の例のように)または"$@"スカラーコンテキストで(2番目の例のように)使用することはほとんど意味がありません。bashシェルでスカラーコンテキストで使用する"$@"ことは、最初の文字を空白に設定するのと同じです。"$*"$IFS

使用するとsnum=( "$@" )配列が作成されますsnum。変数にアクセスすると、$snum配列の最初の要素が得られます。実際にはアクセスと同じです${snum[0]}"${snum[@]}"同様の方法で個別に参照される要素を提供するリストを使用してください"$@"。を使用すると"${snum[*]}"同等の結果が得られますが、"$*"配列の場合ですsnum

snum位置引数リストから配列を作成して空でない場合は、その配列を印刷すると仮定すると、次のようになります。

#!/bin/bash

snum=( "$@" )

if [ "${#snum[@]}" -gt 0 ]; then
    printf '%s\n' "${snum[@]}"
fi

snumスクリプトに引数が指定されると、要素は別々の行に印刷されます。

実行例:

bash-5.1$ ./script 1 2 3 "hello world" 4
1
2
3
hello world
4

このhello worldパラメータは単一のパラメータのままです。いいえ周囲の引用符を忘れた場合、これが発生します$@

コロンで区切られた単一の文字列の位置引数のリストを印刷します。文字列を変更して、位置パラメータ間にコロンを挿入します$IFS

#!/bin/bash

IFS=:
snum="$*"

if [ -n "$snum" ]; then
    printf '%s\n' "$snum"
fi

違いは、snum要素配列ではなく単一の文字列であることです。文字列が空でない場合、つまり空でない引数が 1 つ以上のスクリプトに指定されている場合、スクリプトは文字列を出力します。

snumまたは、引き続き配列として使用されるように、最初の例を少し変更して、

#!/bin/bash

snum=( "$@" )

if [ "${#snum[@]}" -gt 0 ]; then
    IFS=:
    printf '%s\n' "${snum[*]}"
fi

実行例:

bash-5.1$ ./script 1 2 3 "hello world" 4
1:2:3:hello world:4

答え2

var=( values )

配列変数の割り当て

var=value

はスカラー変数の割り当てです(そして、次のようvar="$@"var位置引数とスペースを連結して割り当てられます)。一つスカラなので文字列です)

$var配列の要素はインデックス0の要素に展開されます。これは${var[0]}配列のすべての要素に必要なものと同じで、${var[@]}Kornシェルからコピーされた誤ったデザインです。

また注:

  • Split + glob演算子は、リストコンテキストで引用されていない引数拡張を保持しますが、これはほとんど望ましくありません。皮肉なことに、上記の引用文を追加する唯一の場所は、引用文を必要としない場所だけです。
  • echo出力のランダムデータには使用できませんbash

希望する場所は次のとおりです。

#! /bin/bash -
print_space_separated() {
  local IFS=' '
  printf '%s\n' "$*"
}

if [ "$#" -gt 0 ]; then
  snum=( "$@" )
  print_space_separated "${snum[@]}"
fi

zshwho の配列設計が の配列設計より近い場合は、次のことができます。cshksh

#! /bin/zsh -
if (( $# > 0 )) {
  snum=( $argv )
  print -r -- $snum
}

(それprint -r自体はkshに由来)

ただし、引用符なしで配列拡張を配置すると、このシェルで引数拡張が発生したときに分割+globなしで空の要素が削除され続けます。これを保存するには、ksh構文が必要です。

#! /bin/zsh -
if (( $# > 0 )) {
  snum=( "$@" )
  print -r -- "${snum[@]}"
}

"${snum[@]}"'に短縮することもできますが"$snum[@]")。

invar="$@"またはには、var="${array[@]}"inの最初の文字とスペースで連結された位置引数varで構成される文字列が含まれます。 POSIX 指定されていない動作は、参照コンテキストとリストコンテキストでのみ使用されます。移植性の最初の文字に関連付けられた位置引数を取得するには、(リストまたは非リストのコンテキストで)を使用します。$IFSzshbash$@$IFS"$*"

配列要素を任意の文字列(の最初の文字を除く)に関連付けるには:のパラメータ$IFS拡張jフラグを使用します。これに相当するものはありません。持っています。zsh${(j[that-string])array}bashfishstring join -- that-string $array

関連情報