次に、この長さが異なる配列を提供し、さらに返す理由をご存知ですか"${distro[@]}"
?
禁煙健康増進協会
#!/bin/bash
. ./two.sh
hello(){
arr=$(get_array)
echo "Length arr:" "${#arr[@]}" # array is not preserved and returns 1, but why?
show_length # returns length as correct 3
}
"$@"
2.sh
#!/bin/bash
get_array(){
distro=("redhat linux" "debian linux" "gentoo linux")
echo "${distro[@]}"
}
show_length(){
distro=("redhat linux" "debian linux" "gentoo linux")
echo "Length distro: ${#distro[@]}"
}
なぜ:
sh ./one.sh hello
Length arr: 1
Length distro: 3
答え1
のある関数では配列を返すことはできませんecho "${distro[@]}"
。それがすることは関数の標準出力で印刷するだけです。これは構造化されていないバイトストリームにすぎず、他の配列要素を分離することはできません。
実際に起こるのは、"${distro[@]}"
さまざまなパラメータに展開され、すべてに渡され、印刷され、echo
スペースecho
に関連付けられていることです。効果的に3要素配列(redhat linux
、、、)を単一の文字列に変換します。debian linux
gentoo linux
redhat linux debian linux gentoo linux
これに応じて、stdoutを文字列として読み込み、.(配列割り当てが含まれ、デフォルト設定を使用して生成されたトークン化とワイルドカードのコマンド置換が適用されます)に割り当てるスカラー割り当てもありarr=$(get_array)
ます。get_array
arr
arr=( $(get_array) )
6つの要素この出力の配列(redhat
、、、、、、、)です。)linux
debian
linux
gentoo
linux
回避策は、改行文字を区切り文字として配列要素を印刷し、通常のトークン化よりもスマートな方法を使用して反対側の配列に読み込むことです。名前配列を内部関数に渡し、その中にデータを格納するようにします。
readarray
(Bash 4.0 ベース) を使用して、1 行に 1 つの値を印刷します。
#!/bin/bash
foo() {
local arr=("foo bar" "doo")
printf "%s\n" "${arr[@]}"
}
readarray -t arr2 < <(foo)
printf "read %d elements: " "${#arr2[@]}"
printf "<%s> " "${arr2[@]}"
printf "\n"
ただし、配列が空の場合は改行printf
文字が印刷され続け、反対側の端の結果は要素の配列になります。
あるいは、NULバイトを区切り文字として(Bash 4.4以降)、任意の配列要素を渡し、空の配列の問題を解決することもできます。
#!/bin/bash
foo() {
local arr=("foo bar" $'new\nline')
if (( ${#arr[@]} )); then
printf "%s\0" "${arr[@]}"
fi
}
readarray -t -d '' arr2 < <(foo)
# use declare -p for unambiguous shell-quoted output
declare -p arr2
または、変数名を渡してnamerefを使用してください。
#!/bin/bash
bar() {
local arr=("foo bar" "doo")
declare -n _name="$1"
_name=("${arr[@]}")
}
bar arr2
printf "got %d elements: " "${#arr2[@]}"
printf "<%s> " "${arr2[@]}"
printf "\n"