บรรทัดใหม่ในตัวแปรทุบตี


9

ฉันพยายามเก็บหลายบรรทัดในตัวแปร bash แต่ดูเหมือนจะไม่ทำงาน

ตัวอย่างเช่นถ้าฉันแสดง/binหนึ่งไฟล์ต่อบรรทัดและเก็บไว้ใน$LSนั้นฉันผ่าน$LSเป็น stdin ไปที่wcมันจะส่งกลับ 1 เสมอ:

$ ls -1 /bin | wc -l
134
$ LS=$(ls -1 /bin); wc -l <<< $LS
1

ถ้าฉันพยายามที่จะส่งออกไปยังหน้าจอฉันได้รับผลลัพธ์ต่าง ๆ : echoพิมพ์บรรทัดทั้งหมดในบรรทัดเดียวในขณะที่printfพิมพ์เฉพาะบรรทัดแรก:

#!/bin/bash
LS=$(ls -1 /bin)
echo $LS
printf $LS

ดังนั้นตัวแปร bash สามารถมีได้หลายบรรทัด?

คำตอบ:


15

คุณต้องใส่เครื่องหมายอัญประกาศเป็นสองเท่า (และคุณควรใส่ เครื่องหมายคำพูดเป็นคู่ในกรณีส่วนใหญ่)

echo "$LS"

แต่อย่าใช้ echoเพื่อพิมพ์เนื้อหาตัวแปรโดยใช้printf แทน :

printf '%s\n' "$LS"

1
เพียงแค่ใส่จุดปลีกย่อยกับคำตอบทั้งหมด: printf คาดว่าสตริงรูปแบบจะเป็นพารามิเตอร์แรกซึ่งเป็นสาเหตุที่พวกเขาไม่เห็นสิ่งที่พวกเขาคาดหวัง หากพวกเขาต้องการที่จะเห็นการขึ้นบรรทัดใหม่ในการส่งออกจาก printf ที่ arbtrarily แยกช่องว่างprintf "%s\n" $LSจะทำ
Jeff Schaller

% ใน LS ควรจะ $ LS, BTW (ฉันไม่สามารถทำเช่นแก้ไขสั้น)
เจฟฟ์ Schaller

ขอบคุณ! แน่นอนว่ามันใช้ได้กับwcคำสั่งและอื่น ๆ ด้วย:wc -l <<< "$LS"
Wizard79

1
@JeffSchaller: ไม่คุณไม่ควรยกเลิกการอ้างถึงตัวแปรในกรณีนี้ให้ใช้printf '%s\n' "$LS"หากคุณต้องการเห็น newline นั่นคือการพิมพ์ผิดแก้ไขมัน!
cuonglm

ทำไมคุณไม่ควรใช้ echo เพื่อพิมพ์ตัวแปร?
123

9

บรรทัดใหม่อยู่ในตัวแปร LS=$(ls -1)ตั้งค่าตัวแปรLSเป็นเอาต์พุตของls -1(ซึ่งสร้างเอาต์พุตเดียวกันกับlsโดยวิธียกเว้นเมื่อเอาต์พุตไปยังเทอร์มินัล) ลบการขึ้นบรรทัดใหม่

ปัญหาคือคุณกำลังลบ newlines เมื่อคุณพิมพ์ค่า ในเชลล์สคริปต์$LSไม่ได้หมายถึง "คุณค่าของตัวแปรLS" มันหมายถึง "นำค่าของLSแบ่งออกเป็นคำตามIFSและตีความแต่ละคำว่าเป็นรูปแบบกลม" ในการรับค่าของLSคุณต้องเขียน"$LS"หรือมากกว่าโดยทั่วไปเพื่อใส่$LSระหว่างเครื่องหมายคำพูดคู่

echo "$LS"พิมพ์ค่าของการยกเว้นในเปลือกหอยบางอย่างที่ตีความตัวอักษรทับขวาและยกเว้นค่าไม่กี่ที่เริ่มต้นด้วยLS-

printf "$LS"พิมพ์ค่าของLSตราบใดที่มันไม่ได้มีร้อยละหรือทับขวาใด ๆ ที่ตัวอักษรและ (กับการใช้งานมากที่สุด) -ไม่ได้เริ่มต้นด้วย

หากต้องการพิมพ์ค่าของตรงการใช้งานLS หากคุณต้องการขึ้นบรรทัดใหม่ที่สิ้นสุดการใช้งานprintf %s "$LS"printf '%s\n' "$LS"

โปรดทราบว่า$(ls)โดยทั่วไปรายการไฟล์ในไดเรกทอรีปัจจุบันจะไม่ ใช้งานได้เมื่อคุณมีชื่อไฟล์ที่เชื่องเพียงพอ ที่จะได้รับรายชื่อไฟล์ (ยกเว้นไฟล์ dot), *คุณจำเป็นต้องใช้สัญลักษณ์แทน: ผลลัพธ์คือรายการของสตริงไม่ใช่สตริงดังนั้นคุณจึงไม่สามารถกำหนดให้กับตัวแปรสตริงได้ คุณสามารถใช้ตัวแปรอาเรย์files=(*)ในเชลล์ที่สนับสนุนพวกมัน (ksh93, bash, zsh)

สำหรับข้อมูลเพิ่มเติมให้ดูที่เหตุใดเชลล์สคริปต์ของฉันจึงสำลักช่องว่างหรืออักขระพิเศษอื่น ๆ


printf "$ LS" ก็ยอมจำนนต่อการแยกอักขระแบ็กสแลชคล้ายกับ echo
cnst

0

ดังกล่าวข้างต้น

printf '%s\n' "$LS"

เป็นทางออกที่ถูกต้องเท่านั้น

ให้ฉันแสดงให้เห็นว่าโซลูชันที่เสนออื่น ๆ ทั้งที่มีechoและprintfไม่ทำงานอย่างถูกต้อง:

$ mkdir t
$ cd t
$ touch \\n
$ LS=$(ls -l)
$ echo "$LS"
total 0
-rw-r--r--  1 domain  domain  0 Nov  5 06:12

$ printf "$LS\n"
total 0
-rw-r--r--  1 domain  domain  0 Nov  5 06:12

$ printf '%s\n' "$LS"
total 0
-rw-r--r--  1 domain  domain  0 Nov  5 06:12 \n
$ ls -l
total 0
-rw-r--r--  1 domain  domain  0 Nov  5 06:12 \n
$ rm \\n
$ cd ..
$ rmdir t
$

(หนึ่งสามารถทดสอบด้วยV=$(printf 'line0:\\n\\n\nline1.\n') printf '%s\n' "$V"และรูปแบบต่างๆ)

\nในขณะที่ชื่อไฟล์อาจไม่เหมือนกันเก็บไว้git diffในตัวแปรและโอกาสของคุณในการเผชิญกับการ\nเพิ่มขึ้นอย่างแท้จริง


โปรดทราบว่าkshและzshยังสนับสนุนprint -r -- "$LS"และนอกจากนี้ยังมีzsh มีที่ไม่ได้ส่งออกอักขระขึ้นบรรทัดใหม่ถ้า $ LS ว่างเปล่าและการรับค่าหลายบรรทัดลงใน $ LS ในตอนแรกค่อนข้างยุ่งยากใน csh echo -E - $LScshecho $LS:q
Stéphane Chazelas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.