การอ่านสตริงที่มีการคั่นลงในอาร์เรย์ใน Bash


206

ฉันมีตัวแปรที่มีสตริงคั่นด้วยช่องว่าง:

line="1 1.50 string"

ฉันต้องการแยกสตริงนั้นด้วยช่องว่างเป็นตัวคั่นและเก็บผลลัพธ์ไว้ในอาร์เรย์ดังนั้นต่อไปนี้:

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

เอาท์พุท

1
1.50
string

บางแห่งฉันพบวิธีแก้ปัญหาที่ใช้งานไม่ได้:

arr=$(echo ${line})

ถ้าฉันใช้คำสั่ง echo ข้างต้นหลังจากนี้ฉันจะได้รับ:

1 1.50 string
[empty line]
[empty line]

ฉันก็ลอง

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

ด้วยผลลัพธ์เดียวกัน มีคนช่วยได้ไหม


ดูคำตอบนี้บน Unix และ Linux Stack แลกเปลี่ยน: การใช้ sed กับ herestring (<<<) และอ่าน -a ดูเหมือนว่าจะเร็วกว่าset -f; arr=($string); set +f read -r -a <<< $string
codeforester

คำตอบ:


331

ในการแปลงสตริงเป็นอาร์เรย์โปรดใช้

arr=($line)

หรือ

read -a arr <<< $line

มันเป็นสิ่งสำคัญที่จะไม่ใช้เครื่องหมายคำพูดตั้งแต่ทำกลอุบาย


7
และทำการตรวจสอบสติของอาร์เรย์ใหม่ที่สวยงามของคุณ:for i in ${arr[@]}; do echo $i; done
Banjer

5
หรือเพียงแค่echo ${arr[@]}
Banjer

13
ทั้งสองวิธีอาจล้มเหลวหาก$lineมีตัวอักษรกลมอยู่ในนั้น mkdir x && cd x && touch A B C && line="*" arr=($line); echo ${#arr[@]}ให้ 3
Tino

3
declare -a "arr=($line)"จะเพิกเฉยIFSตัวคั่นภายในสตริงที่ยกมา
เดฟ

4
@Tino ไม่เมื่อline='*', read -a arr <<<$lineการทำงานเสมอ แต่arr=($line)ล้มเหลว
Johnny Wong

39

ลองสิ่งนี้:

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

5
นิสัยดี - วิธีนี้ใช้กับเชลล์ Z ด้วยซึ่งวิธีอื่นด้านบนล้มเหลว
Keith Hughitt

คุณช่วยอธิบายหน่อยได้ไหมว่าทำไมมันถึงได้ผล
smartwjw

2
หมายเหตุ: วิธีนี้จะไม่ทำงานเมื่อบรรทัดมี '*' อยู่ในนั้นเช่นline='*'
Johnny Wong

34

ใน: arr=( $line ). "แยก" มาเกี่ยวข้องกับ "glob"
สัญลักษณ์แทน ( *, ?และ[]) จะขยายไปยังชื่อไฟล์ที่ตรงกัน

วิธีการแก้ไขที่ถูกต้องนั้นซับซ้อนกว่าเล็กน้อย:

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

ไม่มีปัญหากลม อักขระแยกตั้งอยู่ใน$IFSตัวแปรที่ยกมา


5
นี่ควรเป็นคำตอบที่ยอมรับได้ คำสั่งarr=($line)ในคำตอบที่ยอมรับนั้นได้รับผลกระทบจากปัญหาการวนซ้ำ ตัวอย่างเช่นลอง: line="twinkling *"; arr=($line); declare -p arr.
codeforester

การอ้างถึงเป็นทางเลือกสำหรับ herestring <<<แต่อาจเป็นความคิดที่ดีที่จะใช้เครื่องหมายอัญประกาศคู่เพื่อความสอดคล้องและการอ่านได้
codeforester

6

หากคุณต้องการการขยายพารามิเตอร์ให้ลอง:

eval "arr=($line)"

ตัวอย่างเช่นใช้รหัสต่อไปนี้

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

หากไดเรกทอรีปัจจุบันมีไฟล์a.txt, b.txtและc.txtแล้วรันโค้ดจะผลิตผลลัพธ์ต่อไปนี้

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

การวนซ้ำนั้นผิดมันแยกอาเรย์และท่อเข้าไปtrเป็นฟุ่มเฟือย แต่ควรวนซ้ำ"${arr[@]}"แทนไม่ใช่$arr
Zorf
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.