วิธีการส่งออกสตริงหลายบรรทัดใน Bash?


250

ฉันจะส่งออกสตริงหลายบรรทัดใน Bash ได้อย่างไรโดยไม่ต้องใช้การเรียกหลาย ๆ อย่างเช่น:

echo "usage: up [--level <n>| -n <levels>][--help][--version]"
echo 
echo "Report bugs to: "
echo "up home page: "

ฉันกำลังมองหาวิธีพกพาในการทำเช่นนี้โดยใช้ Bash builtins เท่านั้น


4
หากคุณกำลังแสดงข้อความการใช้งานเพื่อตอบสนองการร้องขอที่ไม่ถูกต้องตามปกติคุณจะส่งข้อความนั้นไปยังข้อผิดพลาดมาตรฐานแทนที่จะเป็นเอาต์พุตมาตรฐานโดยecho >&2 ...
Mark Reed

2
@MarkReed ข้อความการใช้งานจะถูกส่งออกโดยการพิมพ์--help(ซึ่งควรจะออกไปมาตรฐาน)
helpermethod

สำหรับคนอื่นที่เข้ามาหาข้อมูลเพิ่มเติมเกี่ยวกับ "เอกสารที่นี่" ได้ที่: tldp.org/LDP/abs/html/here-docs.html
Jeffrey Martinez

ตรวจสอบprintfโซลูชันที่ใช้จาก Gordon Davidson แม้จะอยู่ในเงามืดของวิธีการechoหรือcatตาม แต่ก็ดูเหมือนว่าจะมีตะกอนน้อยกว่ามาก เป็นที่ยอมรับ `printf' ไวยากรณ์แทนบิตของการเรียนรู้ แต่ฉันต้องการที่จะหูของข้อบกพร่องอื่น ๆ (เข้ากันได้ประสิทธิภาพการทำงาน ... ?)
MJV- สนาม

ที่เกี่ยวข้อง: stackoverflow.com/questions/23929235/…
Anton Tarasenko

คำตอบ:


296

เอกสารที่นี่มักใช้เพื่อจุดประสงค์นี้

cat << EOF
usage: up [--level <n>| -n <levels>][--help][--version]

Report bugs to: 
up home page:
EOF

ได้รับการสนับสนุนในเชลล์ที่ได้รับจาก Bourne ทั้งหมดรวมถึง Bash ทุกรุ่น


4
ใช่ - แต่catไม่ใช่ในตัว
Mark Reed

8
@ MarkReed: มันเป็นความจริง แต่ก็มีให้เสมอ (ยกเว้นในกรณีที่อาจผิดปกติ)
หยุดชั่วคราวจนกว่าจะมีการแจ้งให้ทราบต่อไป

6
+1 ขอบคุณ ฉันลงเอยด้วยread -d '' help <<- EOF ...การอ่านสตริงหลายบรรทัดลงในตัวแปรแล้วสะท้อนผลลัพธ์
helpermethod

3
ฉันสามารถบันทึก HEREDOC เป็นตัวแปรได้หรือไม่
chovy

177

หรือคุณสามารถทำสิ่งนี้:

echo "usage: up [--level <n>| -n <levels>][--help][--version]

Report bugs to: 
up home page: "

1
@OliverWeiler: มันจะได้ทำงานในเปลือกหอยบอร์นเช่น Dash และHeirloom บอร์นเชลล์
หยุดชั่วคราวจนกว่าจะมีการแจ้งให้ทราบต่อไป

6
ไม่ดีถ้าคุณต้องการสิ่งนี้ในฟังก์ชั่นเพราะคุณจะต้อง 1) เอาชนะสตริงไปทางด้านซ้ายของไฟล์ของคุณหรือ 2) ให้มันเยื้องเพื่อให้สอดคล้องกับส่วนที่เหลือของรหัสของคุณ แต่แล้วมันพิมพ์ด้วย เยื้องเช่นกัน
sg

43

ได้รับแรงบันดาลใจจากคำตอบที่ลึกซึ้งในหน้านี้ฉันสร้างวิธีผสมผสานซึ่งฉันพิจารณาวิธีที่ง่ายและยืดหยุ่นมากขึ้น คุณคิดอย่างไร?

ก่อนอื่นฉันกำหนดการใช้งานในตัวแปรหนึ่งซึ่งอนุญาตให้ฉันนำมาใช้ซ้ำในบริบทที่แตกต่างกัน รูปแบบง่ายมากเกือบ WYSIWYG โดยไม่จำเป็นต้องเพิ่มอักขระควบคุมใด ๆ ดูเหมือนว่าจะพกพาได้สะดวกสำหรับฉัน (ฉันใช้งานบน MacOS และ Ubuntu)

__usage="
Usage: $(basename $0) [OPTIONS]

Options:
  -l, --level <n>              Something something something level
  -n, --nnnnn <levels>         Something something something n
  -h, --help                   Something something something help
  -v, --version                Something something something version
"

จากนั้นฉันก็สามารถใช้มันเป็น

echo "$__usage"

หรือดียิ่งขึ้นเมื่อแยกพารามิเตอร์ฉันสามารถสะท้อนมันในหนึ่งซับ:

levelN=${2:?"--level: n is required!""${__usage}"}

4
สิ่งนี้ใช้ได้กับฉันในสคริปต์ที่คำตอบข้างต้นไม่ได้ (โดยไม่มีการดัดแปลง)
David Welch

3
สิ่งนี้สะอาดกว่าการเชื่อมโยงอักขระหลายตัวเช่น \ t และ \ n ซึ่งหาได้ยากในข้อความและขยายเพื่อทำให้เอาต์พุตแตกต่างจากสตริงในสคริปต์มาก
sg

1
ด้วยเหตุผลบางอย่างมันพิมพ์ทุกอย่างในบรรทัดเดียวกันสำหรับฉัน: /
Nicolas de Fontenay

2
@ Nicolas: การใช้เครื่องหมายคำพูดคู่echo "$__usage"เป็นสิ่งจำเป็นสำหรับฉัน echo $__usageไม่ทำงาน.
มาริโอ

24

ใช้-eตัวเลือกจากนั้นคุณสามารถพิมพ์อักขระบรรทัดใหม่ด้วย\nในสตริง

ตัวอย่าง (แต่ไม่แน่ใจว่าดีหรือไม่)

สิ่งที่สนุกคือ-eตัวเลือกนั้นไม่ได้จัดทำเป็นเอกสารไว้ในman page ของ MacOSในขณะที่ยังใช้งานได้ มันถูกบันทึกไว้ในหน้าคนของลินุกซ์


6
man page เหล่านั้นมีไว้สำหรับechoคำสั่งที่ระบบจัดให้/bin/echoซึ่งบน Mac OS ไม่มี-eตัวเลือก เมื่อคุณใช้ bash กับระบบเหล่านั้นechoคำสั่งในตัวจะเข้ามาแทนที่ คุณสามารถดูสิ่งนี้ได้โดยการพิมพ์/bin/echo whateverและสังเกตความแตกต่างของพฤติกรรม help echoหากต้องการดูเอกสารสำหรับในตัวชนิด
Mark Reed

1
/bin/echoคือมักจะแตกต่างจากที่หนึ่งไปยังอีก OS และแตกต่างจาก echobuiltin
หยุดชั่วคราวจนกว่าจะมีการแจ้งให้ทราบต่อไป

@ MarkReed: ฉันจะลองใหม่ในภายหลัง แต่ขอบคุณสำหรับข้อมูล +1 ฉันจะทิ้งคำตอบไว้ที่นี่เนื่องจากมีการพูดคุยกันมากมาย
nhahtdh

7
echo -eไม่สามารถพกพาได้ - ตัวอย่างเช่นการนำ echo ไปใช้บางส่วนจะพิมพ์ "-e" เป็นส่วนหนึ่งของเอาต์พุต หากคุณต้องการความสะดวกในการพกพาให้ใช้ printf แทน ตัวอย่างเช่น / bin / echo บน OS X 10.7.4 ทำสิ่งนี้ IIRC bash builtin echo นั้นก็แปลกไปด้วย 10.5.0 แต่ฉันจำรายละเอียดไม่ได้อีกแล้ว
Gordon Davisson

2
echo -eมีกัดฉันก่อน ... แน่นอนใช้printfหรือcatมี heredoc <<-ที่แตกต่างไปจากที่นี่เอกสารที่ดีโดยเฉพาะอย่างยิ่งเพราะคุณสามารถตัดเยื้องชั้นนำในการส่งออก แต่เยื้องเพื่อให้สามารถอ่านในสคริปต์
zbeekman

22

เนื่องจากฉันแนะนำprintfในความคิดเห็นฉันอาจให้ตัวอย่างของการใช้งาน (แม้ว่าสำหรับการพิมพ์ข้อความการใช้งานฉันมีแนวโน้มที่จะใช้คำตอบของ Dennis 'หรือ Chris') เป็นบิตที่ซับซ้อนมากขึ้นกว่าที่จะใช้printf echoอาร์กิวเมนต์แรกคือสตริงรูปแบบซึ่ง\nมีการตีความescapes (เช่น) เสมอ ; มันยังสามารถมีคำสั่งรูปแบบเริ่มต้นด้วย%ซึ่งควบคุมที่ไหนและอย่างไรข้อโต้แย้งเพิ่มเติมจะรวมอยู่ในมัน ต่อไปนี้เป็นวิธีที่แตกต่างกันสองวิธีในการใช้ข้อความการใช้

ก่อนอื่นคุณสามารถรวมข้อความทั้งหมดในสตริงรูปแบบ:

printf "usage: up [--level <n>| -n <levels>][--help][--version]\n\nReport bugs to: \nup home page: \n"

โปรดทราบว่าไม่เหมือนechoกันคุณต้องรวมบรรทัดใหม่สุดท้ายไว้อย่างชัดเจน นอกจากนี้ถ้าข้อความที่เกิดขึ้นกับมีการใด ๆตัวละครที่พวกเขาจะต้องมีการเขียนเป็น% %%หากคุณต้องการรวมที่อยู่บั๊กพอร์ตและที่อยู่โฮมเพจไว้พวกเขาสามารถเพิ่มได้อย่างเป็นธรรมชาติ:

printf "usage: up [--level <n>| -n <levels>][--help][--version]\n\nReport bugs to: %s\nup home page: %s\n" "$bugreport" "$homepage"

ประการที่สองคุณสามารถใช้สตริงรูปแบบเพื่อพิมพ์อาร์กิวเมนต์เพิ่มเติมแต่ละบรรทัดแยกกัน:

printf "%s\n" "usage: up [--level <n>| -n <levels>][--help][--version]" "" "Report bugs to: " "up home page: "

ด้วยตัวเลือกนี้การเพิ่มที่อยู่ของรายงานบั๊กและหน้าแรกจะค่อนข้างชัดเจน:

printf "%s\n" "usage: up [--level <n>| -n <levels>][--help][--version]" "" "Report bugs to: $bugreport" "up home page: $homepage"

9

นอกจากนี้ยังมีซอร์สโค้ดที่เยื้องคุณสามารถใช้<<-(ที่มีเส้นประต่อท้าย) เพื่อละเว้นแท็บนำหน้า (แต่ไม่ใช่ช่องว่างนำหน้า) เช่นนี้

if [ some test ]; then
    cat <<- xx
        line1
        line2
xx
fi

เอาต์พุตข้อความที่เยื้องโดยไม่มีช่องว่างนำหน้า:

line1
line2

นั่นไม่ได้ผลสำหรับฉัน คุณใช้เปลือกอะไร
four43

ไม่ทำงานใน bash 4.4.19 ใน Ubuntu ไม่ได้ลบช่องว่างก่อน
บรรทัด 1 และบรรทัด 2

1
@ four43 คุณพูดถูก ไม่ทำงานเพื่อลบช่องว่างนำหน้า อย่างไรก็ตามจะลบแท็บนำออก ดังนั้นฉันจึงแก้ไขคำตอบจากแท็บและช่องว่างเป็นแท็บไม่ใช่ช่องว่าง ขออภัยในความผิดพลาด ฉันตรวจสอบคู่มือและเห็นได้ชัดว่าเพิ่งมีการลบแท็บ ขอขอบคุณที่แจ้งเรื่องนี้ให้ฉันทราบ
มุมมองรูปไข่

0

หากคุณใช้โซลูชันจาก @jorge และพบว่าทุกอย่างอยู่ในบรรทัดเดียวกันตรวจสอบให้แน่ใจว่าคุณใส่ตัวแปรในเครื่องหมายคำพูด:

echo $__usage

จะพิมพ์ทุกอย่างในบรรทัดเดียว

echo "$__usage"

จะรักษาบรรทัดใหม่


นี่เป็นทางออกเดียวที่เหมาะกับฉัน Printf ทำสิ่งต่าง ๆ มากมายและด้วย multiline xml ของฉันมันอาจต้องหลบหนีออกมามากมายเพราะมันทำให้เนื้อหายุ่งเหยิงไปหมด ฉันกำหนด foo = cat <<EOF .... EOF&& echo "$ foo"
Jilles van Gurp
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.