Bash スクリプトで、行を分割して配列に格納したいと考えています。
たとえば、次の行があるとします。
Paris, France, Europe
結果の配列を次のようにしたいと思います。
array[0] = Paris
array[1] = France
array[2] = Europe
シンプルな実装が望ましいです。速度は問題ではありません。どうすればいいですか?
IFS=', ' read -r -a array <<< "$string"
の文字は個別にセパレータとして扱われることに注意してください$IFS
。この場合、フィールドは2 つの文字のシーケンスではなく、コンマまたはスペースで区切られます。興味深いことに、スペースは特別に扱われるため、入力にコンマ スペースが含まれている場合、空のフィールドは作成されません。
個々の要素にアクセスするには:
echo "${array[0]}"
要素を反復処理するには:
for element in "${array[@]}"
do
echo "$element"
done
インデックスと値の両方を取得するには:
for index in "${!array[@]}"
do
echo "$index ${array[index]}"
done
最後の例は、Bash 配列がまばらであるため便利です。つまり、要素を削除したり要素を追加したりすると、インデックスが連続しなくなります。
unset "array[1]"
array[42]=Earth
配列内の要素数を取得するには:
echo "${#array[@]}"
前述のように、配列はまばらになる可能性があるため、最後の要素を取得するために長さを使用しないでください。Bash 4.2 以降でできることは次のとおりです。
echo "${array[-1]}"
Bashの任意のバージョン(2.05b以降のどこかから):
echo "${array[@]: -1:1}"
負のオフセットを大きくすると、配列の末尾から離れた場所が選択されます。古い形式のマイナス記号の前のスペースに注意してください。必須です。
IFSを設定しない方法は次のとおりです。
string="1:2:3:4:5"
set -f # avoid globbing (expansion of *).
array=(${string//:/ })
for i in "${!array[@]}"
do
echo "$i=>${array[i]}"
done
アイデアは文字列置換を使用しています:
${string//substring/replacement}
$substring のすべての一致を空白に置き換えてから、置換された文字列を使用して配列を初期化します。
(element1 element2 ... elementN)
注:この回答は、分割+グロブ演算子を利用しています。したがって、一部の文字 ( など*
) の展開を防ぐには、このスクリプトのグロビングを一時停止することをお勧めします。
t="one,two,three"
a=($(echo "$t" | tr ',' '\n'))
echo "${a[2]}"
3枚印刷
受け入れられた回答は、1行の値に対して機能します。
変数に複数の行がある場合:
string='first line
second line
third line'
すべての行を取得するには、非常に異なるコマンドが必要です。
while read -r line; do lines+=("$line"); done <<<"$string"
または、はるかに単純な bash readarray :
readarray -t lines <<<"$string"
printf 機能を利用すると、すべての行を非常に簡単に印刷できます。
printf ">[%s]\n" "${lines[@]}"
>[first line]
>[ second line]
>[ third line]
特に区切り文字が改行の場合、受け入れられた回答に記載されている方法が機能しないことが時々ありました。
そのような場合、私はこのように解決しました:
string='first line
second line
third line'
oldIFS="$IFS"
IFS='
'
IFS=${IFS:0:1} # this is useful to format your code with tabs
lines=( $string )
IFS="$oldIFS"
for line in "${lines[@]}"
do
echo "--> $line"
done
これは私にとってOSXで機能します:
string="1 2 3 4 5"
declare -a array=($string)
文字列に異なる区切り文字がある場合は、最初にそれらをスペースに置き換えます。
string="1,2,3,4,5"
delimiter=","
declare -a array=($(echo $string | tr "$delimiter" " "))
単純 :-)
これはJmoney38 によるアプローチに似ていますが、sed を使用します。
string="1,2,3,4"
array=(`echo $string | sed 's/,/\n/g'`)
echo ${array[0]}
プリント 1
これを試して
IFS=', '; array=(Paris, France, Europe)
for item in ${array[@]}; do echo $item; done
それは簡単です。必要に応じて、宣言を追加することもできます (また、コンマを削除することもできます)。
IFS=' ';declare -a array=(Paris France Europe)
上記を元に戻すためにIFSが追加されていますが、新しいbashインスタンスではそれがなくても機能します
IFS を変更せずにそれを行う別の方法:
read -r -a myarray <<< "${string//, /$IFS}"
目的の区切り文字に一致するように IFS を変更するのではなく、目的の区切り文字のすべての出現箇所をviaの内容に置き換えることができます。", "
$IFS
"${string//, /$IFS}"
ただし、非常に大きな文字列の場合、これは遅くなるでしょうか?
これは、Dennis Williamson の回答に基づいています。
別のアプローチは次のとおりです。
str="a, b, c, d" # assuming there is a space after ',' as in Q
arr=(${str//,/}) # delete all occurrences of ','
この 'arr' の後に、4 つの文字列を含む配列が続きます。これは、IFS や読み取り、その他の特別な処理を必要としないため、はるかに単純で直接的です。