819

Bash スクリプトで、行を分割して配列に格納したいと考えています。

たとえば、次の行があるとします。

Paris, France, Europe

結果の配列を次のようにしたいと思います。

array[0] = Paris
array[1] = France
array[2] = Europe

シンプルな実装が望ましいです。速度は問題ではありません。どうすればいいですか?

4

21 に答える 21

1344
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}"

負のオフセットを大きくすると、配列の末尾から離れた場所が選択されます。古い形式のマイナス記号の前のスペースに注意してください。必須です。

于 2012-05-14T15:16:48.597 に答える
250

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)

注:この回答は、分割+グロブ演算子を利用しています。したがって、一部の文字 ( など*) の展開を防ぐには、このスクリプトのグロビングを一時停止することをお勧めします。

于 2013-03-14T02:20:13.680 に答える
121
t="one,two,three"
a=($(echo "$t" | tr ',' '\n'))
echo "${a[2]}"

3枚印刷

于 2015-07-14T11:54:19.137 に答える
32

受け入れられた回答は、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]
于 2015-07-24T21:24:27.003 に答える
31

特に区切り文字が改行の場合、受け入れられた回答に記載されている方法が機能しないことが時々ありました。
そのような場合、私はこのように解決しました:

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
于 2012-11-02T13:44:37.083 に答える
12

これは私にとって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" " "))

単純 :-)

于 2019-05-15T09:03:02.900 に答える
9

これはJmoney38 によるアプローチに似ていますが、sed を使用します。

string="1,2,3,4"
array=(`echo $string | sed 's/,/\n/g'`)
echo ${array[0]}

プリント 1

于 2016-06-03T15:24:19.477 に答える
2

これを試して

IFS=', '; array=(Paris, France, Europe)
for item in ${array[@]}; do echo $item; done

それは簡単です。必要に応じて、宣言を追加することもできます (また、コンマを削除することもできます)。

IFS=' ';declare -a array=(Paris France Europe)

上記を元に戻すためにIFSが追加されていますが、新しいbashインスタンスではそれがなくても機能します

于 2016-03-04T06:02:07.580 に答える
1

IFS を変更せずにそれを行う別の方法:

read -r -a myarray <<< "${string//, /$IFS}"

目的の区切り文字に一致するように IFS を変更するのではなく、目的の区切り文字のすべての出現箇所をviaの内容に置き換えることができます。", "$IFS"${string//, /$IFS}"

ただし、非常に大きな文字列の場合、これは遅くなるでしょうか?

これは、Dennis Williamson の回答に基づいています。

于 2018-05-31T05:56:22.787 に答える
-3

別のアプローチは次のとおりです。

str="a, b, c, d"  # assuming there is a space after ',' as in Q
arr=(${str//,/})  # delete all occurrences of ','

この 'arr' の後に、4 つの文字列を含む配列が続きます。これは、IFS や読み取り、その他の特別な処理を必要としないため、はるかに単純で直接的です。

于 2016-09-13T16:21:10.617 に答える