Đọc một chuỗi phân cách thành một mảng trong Bash


206

Tôi có một biến chứa chuỗi phân cách bằng dấu cách:

line="1 1.50 string"

Tôi muốn chia chuỗi đó với dấu cách là dấu phân cách và lưu kết quả vào một mảng, sao cho như sau:

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

đầu ra

1
1.50
string

Ở đâu đó tôi đã tìm thấy một giải pháp không hiệu quả:

arr=$(echo ${line})

Nếu tôi chạy các câu lệnh echo ở trên sau này, tôi nhận được:

1 1.50 string
[empty line]
[empty line]

Tôi cũng đã thử

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

với kết quả tương tự. Ai đó có thể giúp đỡ không?


Xem câu trả lời này trên Unix & Linux Stack Exchange: Sử dụng sed với herestring (<<<) và đọc -a . set -f; arr=($string); set +fcó vẻ là nhanh hơn read -r -a <<< $string.
codeforester

Câu trả lời:


331

Để chuyển đổi một chuỗi thành một mảng, vui lòng sử dụng

arr=($line)

hoặc là

read -a arr <<< $line

Điều quan trọng là không sử dụng dấu ngoặc kép vì điều này không có mẹo.


7
và để kiểm tra sự tỉnh táo của mảng mới tuyệt đẹp của bạn:for i in ${arr[@]}; do echo $i; done
Banjer

5
hoặc chỉecho ${arr[@]}
Banjer

13
Cả hai cách có thể thất bại nếu $linecó các ký tự toàn cầu trong đó. mkdir x && cd x && touch A B C && line="*" arr=($line); echo ${#arr[@]}tặng 3
Tino

3
declare -a "arr=($line)"sẽ bỏ qua các IFSdấu phân cách bên trong các chuỗi được trích dẫn
Dave

4
@Tino số Khi line='*', read -a arr <<<$lineluôn luôn làm việc, nhưng chỉ arr=($line)thất bại.
Johnny Wong

39

Thử cái này:

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

5
Nice - Giải pháp này cũng hoạt động trong shell Z khi một số cách tiếp cận khác ở trên không thành công.
Keith Hughitt

Nó không hoạt động, bạn có thể giải thích tại sao nó hoạt động?
smartwjw

2
Lưu ý: điều này cũng không hoạt động khi dòng có '*' trong đó, giống nhưline='*'
Johnny Wong

34

Trong : arr=( $line ). "Tách" đi kèm với "toàn cầu".
Các kí hiệu ( *, ?[]) sẽ được mở rộng để tên tập tin phù hợp.

Giải pháp đúng chỉ phức tạp hơn một chút:

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

Không có vấn đề toàn cầu; ký tự phân chia được đặt trong $IFS, các biến được trích dẫn.


5
Đây phải là câu trả lời được chấp nhận. Các tuyên bố arr=($line)trong câu trả lời được chấp nhận bị các vấn đề toàn cầu. Ví dụ: thử : line="twinkling *"; arr=($line); declare -p arr.
tiền mã hóa

Trích dẫn là tùy chọn để trích dẫn, <<<nhưng có thể vẫn nên sử dụng dấu ngoặc kép để thống nhất và dễ đọc.
codeforester 20/03/18

6

Nếu bạn cần mở rộng tham số, hãy thử:

eval "arr=($line)"

Ví dụ, lấy mã sau đây.

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

Nếu thư mục hiện tại chứa các tệp a.txt, b.txtc.txtsau đó thực thi mã sẽ tạo ra đầu ra sau.

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

Vòng lặp là sai, nó phân chia mảng tốt và đường ống vào trlà thừa nhưng "${arr[@]}"thay vào đó, nó sẽ lặp lại , không phải$arr
Zorf
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.