พิมพ์องค์ประกอบอาร์เรย์ในบรรทัดแยกต่างหากใน Bash?


229

ฉันจะพิมพ์องค์ประกอบอาเรย์ของ Bash Array ในแต่ละบรรทัดได้อย่างไร? อันนี้ใช้ได้ แต่มีวิธีที่ดีกว่า:

$ my_array=(one two three)
$ for i in ${my_array[@]}; do echo $i; done
one
two
three

พยายามตัวนี้ แต่มันไม่ทำงาน:

$ IFS=$'\n' echo ${my_array[*]}
one two three

คำตอบ:


436

ลองทำสิ่งนี้:

$ printf '%s\n' "${my_array[@]}"

ความแตกต่างระหว่าง$@และ$*:

  • ไม่ได้ระบุผลลัพธ์จะไม่ถูกระบุ ใน Bash ทั้งคู่จะขยายเพื่อแยก args จากนั้น wordplit และ globed

  • อ้างถึง, "$@"ขยายแต่ละองค์ประกอบเป็นอาร์กิวเมนต์ที่แยกต่างหากในขณะที่"$*" ขยายไปยัง args ที่รวมกันเป็นหนึ่งอาร์กิวเมนต์: "$1c$2c..."(โดยที่cเป็นอักขระตัวแรกของIFS)

"$@"คุณมักจะต้องการ "${arr[@]}"เดียวกันจะไปสำหรับ

มักจะพูดพวกเขา!


5
และโปรดทราบว่าอัญประกาศคู่รอบการอ้างอิงตัวแปรมีความสำคัญหากคุณต้องการให้แน่ใจว่าองค์ประกอบที่มีช่องว่างภายในจะไม่แยกโดยไม่ตั้งใจ
danfuzz

4
@sputnick: ใช้งานไม่ได้องค์ประกอบอาร์เรย์สิ้นสุดในบรรทัดเดียว
Axel Bregnsbo

1
เครื่องหมายยัติภังค์สองแบบคืออะไรหลังจากมีคำสั่งแล้ว ฉันไม่พบการอ้างอิงใด ๆ ในคู่มือ
joanpau

3
มีวิธีที่จะทำให้มันไม่มีบรรทัดว่างถ้าไม่มีองค์ประกอบในอาร์เรย์โดยไม่ต้อง| grep -v '^$'?
Noel Yap

2
@espaciomore '% s \ n' เป็นรูปแบบสำหรับเอาต์พุตของฟังก์ชัน printf % s หมายถึงตัวยึดตำแหน่งสำหรับอาร์กิวเมนต์สตริง (ในกรณีนี้องค์ประกอบอาร์เรย์) และ \ n เพิ่มตัวแบ่งบรรทัดหลังจากนั้น ดังนั้นจะมีสตริงและตัวแบ่งบรรทัดในเอาต์พุตสำหรับแต่ละองค์ประกอบในอาร์เรย์
Koja

71

เพียงแค่อ้างอาร์กิวเมนต์เพื่อสะท้อน:

( IFS=$'\n'; echo "${my_array[*]}" )

เชลล์ย่อยช่วยกู้คืน IFS หลังการใช้งาน


3
ขออภัย perreal ฉันย้ายเครื่องหมายถูกไปที่ sputnick แม้จะชอบวิธีการแก้ปัญหาของคุณดีขึ้นเพียงเพราะฉันได้เรียนรู้เกี่ยวกับฟังก์ชั่น 'printf'
Axel Bregnsbo

3
ขอบคุณสำหรับคำตอบนี้ - ฉันชอบ! การมอบหมายที่แย่เกินไปเกิดขึ้นหลังจากการขยายจึงIFS=$'\n' echo "${my_array[*]}"ไม่ทำงาน โอ้ดี!
cxw

@cxw คุณหมายถึงอะไรโดย "การมอบหมายให้เกิดขึ้น"
Steven Shaw

1
@bschlueter ฉันลองกับ Bash 4 - 4.4.23 (1) -release - และมันใช้งานได้!
Steven Shaw

1
@cxw อ่าฉันไม่เห็นว่าคุณพยายามทำอะไรที่นั่น ฉันคิดว่ามันใช้งานไม่ได้เพราะechoเป็น builtin ใน Bash อย่างไรก็ตามคุณสามารถห่อมันในฟังก์ชั่นและมันจะทำงาน! gist.github.com/steshaw/53ba0095bce8ccab52d26a14375dedb8
สตีเวนชอว์

40

ใช้สำหรับ :

for each in "${alpha[@]}"
do
  echo "$each"
done

ใช้ประวัติศาสตร์ ; โปรดทราบว่าสิ่งนี้จะล้มเหลวหากค่าของคุณมี!:

history -p "${alpha[@]}"

ใช้basename ; โปรดทราบว่าสิ่งนี้จะล้มเหลวหากค่าของคุณมี/:

basename -a "${alpha[@]}"

ใช้shuf ; โปรดทราบว่าผลลัพธ์อาจไม่ออกมาตามลำดับ:

shuf -e "${alpha[@]}"

19
"shuf" ... "อาจไม่ออกคำสั่ง" ... เฮฮา
Walf

4
สำหรับ shuf ใครจะมีความคิดที่จะใช้สิ่งนั้น
fbicknel

3

ฉันลองคำตอบที่นี่ในรูปยักษ์สำหรับ ... ถ้าวนรอบ แต่ไม่ได้รับความสุข - ดังนั้นฉันจึงทำแบบนี้อาจยุ่ง แต่ก็ทำงาน:

 # EXP_LIST2 is iterated    
 # imagine a for loop
     EXP_LIST="List item"    
     EXP_LIST2="$EXP_LIST2 \n $EXP_LIST"
 done 
 echo -e $EXP_LIST2

แม้ว่านั่นจะเป็นการเพิ่มช่องว่างในรายการซึ่งก็ดี - ฉันต้องการให้เยื้องเล็กน้อย นอกจากนี้สมมติว่า "\ n" สามารถพิมพ์ใน $ EP_LIST ดั้งเดิมได้


5
ดูไม่เหมือนตัวอย่างที่สมบูรณ์
kenorb

3

อีกตัวแปรที่มีประโยชน์คือไพพ์ถึงtr:

echo "${my_array[@]}" | tr ' ' '\n'

มันดูเรียบง่ายและกะทัดรัด


11
ยกเว้นช่วงเวลานี้ในmy_array=( "one two" three )
ไมค์โฮลท์

แก้ไขด้วยเครื่องหมายคำพูดคู่
สตีเวนชอว์

ใช้งานไม่ได้ตามที่โฆษณาใน Bash เวอร์ชัน4+ ต้องใช้echo "${my_array[@]}" | tr '' ' \n'แม้ว่าโดยส่วนตัวแล้วฉันจะหลีกเลี่ยงการใช้echoแบบนั้นซึ่งtrตัวเลือกของฉันฉันคิดว่าบางสิ่งบางอย่างtr '' ' \n' <<<"${my_array[@]}"อาจจะง่ายต่อการอ่านในภายหลัง
S0AndS0
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.