Membaca string yang dibatasi menjadi array di Bash


207

Saya memiliki variabel yang berisi string yang dibatasi ruang:

line="1 1.50 string"

Saya ingin membagi string itu dengan spasi sebagai pembatas dan menyimpan hasilnya dalam array, sehingga berikut ini:

echo ${arr[0]}
echo ${arr[1]}
echo ${arr[2]}

output

1
1.50
string

Di suatu tempat saya menemukan solusi yang tidak berhasil:

arr=$(echo ${line})

Jika saya menjalankan pernyataan gema di atas setelah ini, saya mendapatkan:

1 1.50 string
[empty line]
[empty line]

Saya juga mencoba

IFS=" "
arr=$(echo ${line})

dengan hasil yang sama. Bisakah seseorang membantu?


Lihat jawaban ini di Unix & Linux Stack Exchange: Menggunakan sed dengan herestring (<<<) dan baca -a . set -f; arr=($string); set +ftampaknya lebih cepat daripada read -r -a <<< $string.
codeforester

Jawaban:


332

Untuk mengkonversi string menjadi array, silakan gunakan

arr=($line)

atau

read -a arr <<< $line

Sangat penting untuk tidak menggunakan tanda kutip karena ini berhasil.


7
dan untuk melakukan pemeriksaan kewarasan array baru Anda yang indah:for i in ${arr[@]}; do echo $i; done
Banjer

5
atau hanyaecho ${arr[@]}
Banjer

13
Kedua cara mungkin gagal jika $linememiliki karakter globbing di dalamnya. mkdir x && cd x && touch A B C && line="*" arr=($line); echo ${#arr[@]}memberi 3
Tino

3
declare -a "arr=($line)"akan mengabaikan IFSpembatas di dalam string yang dikutip
Dave

4
@Tino No. Kapan line='*', read -a arr <<<$lineselalu bekerja, tetapi hanya arr=($line)gagal.
Johnny Wong

39

Coba ini:

arr=(`echo ${line}`);

5
Bagus - Solusi ini juga berfungsi di Z shell di mana beberapa pendekatan lain di atas gagal.
Keith Hughitt

Ini berhasil, bisakah Anda menjelaskan mengapa itu berhasil?
smartwjw

2
Catatan: ini tidak berfungsi baik ketika baris memiliki '*' di dalamnya, sepertiline='*'
Johnny Wong

34

Dalam: arr=( $line ). "Split" dikaitkan dengan "glob".
Wildcard ( *, ?dan []) akan diperluas ke nama file yang cocok.

Solusi yang benar hanya sedikit lebih kompleks:

IFS=' ' read -a arr <<< "$line"

Tidak ada masalah menggumpal; karakter split diatur $IFS, variabel yang dikutip.


5
Ini harus menjadi jawaban yang diterima. Pernyataan arr=($line)dalam jawaban yang diterima menderita masalah globbing. Sebagai contoh, cobalah: line="twinkling *"; arr=($line); declare -p arr.
codeforester

Mengutip adalah opsional untuk herestring, <<<tetapi mungkin ide yang baik untuk tetap menggunakan tanda kutip ganda untuk konsistensi dan keterbacaan.
codeforester

7

Jika Anda membutuhkan ekspansi parameter, cobalah:

eval "arr=($line)"

Misalnya, ambil kode berikut.

line='a b "c d" "*" *'
eval "arr=($line)"
for s in "${arr[@]}"; do 
    echo "$s"
done

Jika direktori saat ini berisi file a.txt, b.txtdan c.txt, mengeksekusi kode akan menghasilkan output berikut.

a
b
c d
*
a.txt
b.txt
c.txt

-9
line="1 1.50 string"

arr=$( $line | tr " " "\n")

for x in $arr
do
echo "> [$x]"
done

Perulangan salah, ia membagi array dengan baik dan pipa menjadi trberlebihan tetapi harus melewatinya "${arr[@]}", bukan$arr
Zorf
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.