วิธีเพิ่มบรรทัดใหม่ในตัวแปรในสคริปต์ทุบตี


64

เมื่อฉันทำ

str="Hello World\n===========\n"

ฉันก็\nพิมพ์ออกมาเหมือนกัน ฉันจะมีการขึ้นบรรทัดใหม่ได้อย่างไร


1
ในขณะที่คำตอบที่นี่ยอดเยี่ยม แต่ในความเป็นจริงฉันคิดว่าคุณควรจะใช้อาร์เรย์สำหรับสิ่งนี้เป็นส่วนใหญ่
evilsoup

ดูเพิ่มเติมคำถามที่พยายามที่จะฝังขึ้นบรรทัดใหม่ในตัวแปรในการทุบตี
HelloGoodbye

คำตอบ:


73

ในbashคุณสามารถใช้ไวยากรณ์

str=$'Hello World\n===========\n'

เครื่องหมายคำพูดเดี่ยวที่นำหน้าด้วย a $คือไวยากรณ์ใหม่ที่อนุญาตให้แทรกลำดับ escape ในสตริง

printfbuiltin ยังช่วยให้สามารถบันทึกผลลัพธ์ที่ส่งออกไปยังตัวแปร

printf -v str 'Hello World\n===========\n'

วิธีแก้ปัญหาทั้งสองไม่จำเป็นต้องใช้ subshell

หากในสิ่งต่อไปนี้คุณต้องพิมพ์สตริงคุณควรใช้เครื่องหมายคำพูดคู่ในตัวอย่างต่อไปนี้:

echo "$str"

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


1
ไวยากรณ์ที่str=$'Hello World\n===========\n'เรียกว่าคืออะไร? การทดแทนตัวแปร?
zengr

5
@zengr: มันถูกเรียกว่าANSI-C quotingและยังรองรับzshและksh; อย่างไรก็ตามมันไม่เป็นไปตาม POSIX
mklement0

4
@ mkelement0 มาจาก ksh93 และยังรองรับโดย zsh, bash, mksh และ FreeBSD sh และการรวมไว้ในการแก้ไขครั้งสำคัญครั้งต่อไปของ POSIX อยู่ภายใต้การสนทนา
Stéphane Chazelas

1
ดูเหมือนจะไม่ทำงานกับคำพูดสองครั้ง? เช่นstr=$"My $PET eats:\n$PET food"? วิธีนี้ใช้ได้กับการเสนอราคาสองครั้ง
Brad Parks

31

คุณสามารถใส่บรรทัดใหม่ตามตัวอักษรในเครื่องหมายคำพูดเดี่ยว (ในเชลล์สไตล์ Bourne / POSIX ใด ๆ )

str='Hello World
===========
'

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

mycommand <<'EOF'
Hello World
===========
EOF

หากคุณต้องการเก็บสตริงในตัวแปรให้ใช้catคำสั่งในการทดแทนคำสั่ง อักขระขึ้นบรรทัดใหม่ที่ท้ายสตริงจะถูกปล้นโดยการทดแทนคำสั่ง หากคุณต้องการเก็บบรรทัดใหม่สุดท้ายให้วางจุกท้ายแล้วถอดออกหลังจากนั้น ในเชลล์ที่สอดคล้องกับ POSIX คุณสามารถเขียนstr=$(cat <<'EOF'); str=${str%a}ตามด้วย heredoc ได้ แต่ bash ต้องการให้ heredoc ปรากฏขึ้นก่อนที่จะปิดวงเล็บ

str=$(cat <<'EOF'
Hello World
===========
a
EOF
); str=${str%a}

ใน ksh, bash และ zsh คุณสามารถใช้$'…'แบบฟอร์มที่ยกมาเพื่อขยายเครื่องหมายทับขวาภายในเครื่องหมายคำพูด

str=$'Hello World\n===========\n'

1
ฉันใช้ GNU ทุบตี 4.1.5 และstr=$(cat <<'EOF')ไม่ทำงานตามที่เป็นอยู่ .. )ความต้องการที่จะอยู่ในบรรทัดถัดไปหลังจากสิ้นสุดเอกสารEOF.. แต่ถึงกระนั้นก็จะสูญเสียการขึ้นบรรทัดใหม่เนื่องจากคำสั่ง การแทน.
Peter.O

@fred คะแนนที่ดีฉันได้อธิบายเกี่ยวกับบรรทัดใหม่ต่อท้ายและรหัสที่แสดงที่ทำงานในทุบตี ฉันคิดว่ามันเป็นข้อผิดพลาดในการทุบตีแม้ว่าจะซื่อสัตย์ในการอ่านข้อมูลจำเพาะ POSIX ฉันพบว่าไม่ชัดเจนว่าพฤติกรรมนั้นได้รับคำสั่งเมื่อ << อยู่ภายในการทดแทนคำสั่งและ heredoc ไม่ใช่
Gilles

สิ่งที่ยอดเยี่ยม; เพื่อรักษา\nอินสแตนซ์ของtrailing (และนำหน้า) ในbashเมื่อจับที่นี่ doc ในตัวแปรพิจารณาIFS= read -r -d '' str <<'EOF'...เป็นทางเลือกแทนวิธี stopper (ดูคำตอบของฉัน)
mklement0

8

คุณใช้ "echo" หรือไม่? ลอง "echo -e"

echo -e "Hello World\n===========\n"

2
BTW คุณไม่จำเป็นต้องมี \ n ขั้นสุดท้ายเนื่องจากechoจะเพิ่มหนึ่งรายการโดยอัตโนมัติเว้นแต่คุณจะระบุ -n (อย่างไรก็ตามความรุนแรงหลักของคำถามคือวิธีการขึ้นบรรทัดใหม่เหล่านี้เป็นตัวแปร)
Peter.O

+1 ของโซลูชั่นทั้งหมดอันนี้ตรงที่สุดและง่ายที่สุด
Hai Vu

echo -e ไม่ทำงานใน OS X
Greg M. Krsak

2
@GregKrsak: ในbash, echo -e ไม่ทำงานบน OS X - นั่นเป็นเพราะechoเป็นทุบตีในตัว (มากกว่าปฏิบัติการภายนอก) -eและในตัวที่ไม่สนับสนุน (ในฐานะ builtin มันควรทำงานบนทุกแพลตฟอร์มที่ทุบตีทำงานโดยบังเอิญecho -eทำงานในkshและzshเกินไป) โดยคมชัด แต่ภายนอกechoยูทิลิตี้ บน OS X - /bin/echo- แน่นอนไม่ได้-eสนับสนุน
mklement0

3

หากคุณต้องการบรรทัดใหม่ในสคริปต์ของคุณหลาย ๆ ครั้งคุณสามารถประกาศตัวแปรโกลบอลที่ถือบรรทัดใหม่ ด้วยวิธีนี้คุณสามารถใช้มันในสตริงที่มีเครื่องหมายคำพูดคู่ (การขยายตัวแปร)

NL=$'\n'
str="Hello World${NL} and here is a variable $PATH ===========${NL}"

ทำไมจะ$''ต้องมี subshell
Mat

ขออภัยฉันตอบผิด
pihentagy

ฉันขอคำอธิบายจากผู้ลงคะแนนได้ไหม?
pihentagy

ดี! สามารถรวมอยู่ในตัวแปรโดยใช้เครื่องหมายคำพูดคู่เช่น"My dog eats:${NL}dog food"
Brad Parks

3

จากการสนทนาทั้งหมดนี่เป็นวิธีที่ง่ายที่สุดสำหรับฉัน:

bash$ str="Hello World
==========="
bash$ echo "$str"
Hello World
===========

ก้องคำสั่งจะต้องใช้คำพูดสอง


3

เพื่อเติมเต็มคำตอบที่มีอยู่แล้วให้ดียิ่งขึ้น:

หากคุณกำลังใช้bashและคุณต้องการใช้การขึ้นบรรทัดใหม่ที่เกิดขึ้นจริงสำหรับการอ่าน , readเป็นตัวเลือกอีกจับนี่ doc ในตัวแปรซึ่ง (เช่นการแก้ปัญหาอื่น ๆ ที่นี่) ไม่จำเป็นต้องใช้ของ subshell

# Reads a here-doc, trimming leading and trailing whitespace.
# Use `IFS= read ...` to preserve it (the trailing \n, here).
read -r -d '' str <<'EOF'   # Use `IFS= read ...` to preserve the trailing \n
Hello World
===========
EOF
# Test: output the variable enclosed in "[...]", to show the value's boundaries.
$ echo "$str"
[Hello World
===========]
  • -rตรวจสอบให้แน่ใจreadว่าไม่ได้ตีความอินพุต (โดยค่าเริ่มต้นมันจะรักษาแบ็คสแลชพิเศษ แต่ก็ไม่ค่อยจำเป็น)

  • -d ''ตั้งค่าตัวคั่น "บันทึก" เป็นสตริงว่างทำให้เกิดreadการอ่านอินพุตทั้งหมดในครั้งเดียว (แทนที่จะเป็นเพียงบรรทัดเดียว)

โปรดทราบว่าการออกจาก$IFS(ตัวคั่นเขตข้อมูลภายใน) เป็นค่าเริ่มต้น$' \t\n'(ช่องว่างแท็บขึ้นบรรทัดใหม่) ช่องว่างนำหน้าและต่อท้ายใด ๆจะถูกตัดออกจากค่าที่กำหนดให้$strซึ่งรวมถึงบรรทัดใหม่ของเอกสารที่นี่
(โปรดสังเกตว่าแม้ว่าร่างกายนี่ doc เริ่มต้นบนเส้นหลังตัวคั่นเริ่มต้น ( 'EOF'ที่นี่) ก็ไม่ได้มีนำขึ้นบรรทัดใหม่)

ปกตินี้เป็นพฤติกรรมที่ต้องการ แต่ถ้าคุณไม่ต้องการที่ท้ายบรรทัดใหม่ใช้IFS= read -r -d ''แทนเพียงread -r -d ''แต่ทราบว่าใด ๆช่องว่างชั้นนำและต่อท้ายจะถูกรักษาไว้แล้ว
(โปรดทราบว่าการเพิ่มIFS= ไปยังreadคำสั่งโดยตรงหมายความว่าการมอบหมายมีผลบังคับใช้ระหว่างคำสั่งนั้นเท่านั้นดังนั้นจึงไม่จำเป็นต้องเรียกคืนค่าก่อนหน้านี้)


การใช้ here-doc ยังช่วยให้คุณสามารถใช้การเยื้องเพื่อตั้งค่าสตริง multiline เพื่อให้สามารถอ่านได้:

# Caveat: indentation must be actual *tab* characters - spaces won't work.
read -r -d '' str <<-'EOF' # NOTE: Only works if the indentation uses actual tab (\t) chars.
    Hello World
    ===========
EOF
# Output the variable enclosed in "[...]", to show the value's boundaries.
# Note how the leading tabs were stripped.
$ echo "$str"
[Hello World
===========]

การวาง-ระหว่าง<<และการเปิด here-doc delimiter ( 'EOF'ที่นี่) ทำให้อักขระแท็บนำหน้าถูกดึงออกจากเนื้อความ here-doc และแม้กระทั่งตัวคั่นการปิด แต่โปรดทราบว่าสิ่งนี้ใช้ได้กับอักขระแท็บจริงเท่านั้นไม่ใช่ช่องว่างดังนั้นหาก บรรณาธิการแปลกดปุ่มแท็บลงในช่องว่างจำเป็นต้องทำงานเพิ่มเติม


-1

คุณต้องทำแบบนี้:

STR=$(echo -ne "Hello World\n===========\n")

ปรับปรุง:

ตามที่เฟร็ดชี้ให้เห็นวิธีนี้คุณจะหลุดตามท้าย "\ n" ในการกำหนดตัวแปรด้วยลำดับแบ็กสแลชที่ขยายให้ทำ:

STR=$'Hello World\n===========\n\n'

มาทดสอบกันเถอะ:

echo "[[$STR]]"

ให้เราตอนนี้:

[[Hello World
===========

]]

โปรดทราบว่า $ '' จะแตกต่างจาก $ "" ที่สองทำการแปลตามสถานที่ปัจจุบัน สำหรับ deital man bashดูในส่วนของข้อความใน


-2
#!/bin/bash

result=""

foo="FOO"
bar="BAR"

result+=$(printf '%s' "$foo")$'\n'
result+=$(printf '%s' "$bar")$'\n'

echo "$result"
printf '%s' "$result"

เอาท์พุท:

FOO
BAR

FOO
BAR

1
ทำไมไม่ง่าย ๆresult+=$foo$'\n'? $(printf %s "$foo")จะตัดแต่งอักขระบรรทัดใหม่ต่อท้ายด้วย$fooถ้ามี
Stéphane Chazelas

ไม่มีคำอธิบายสำหรับรหัสอื่นมันดูดีสำหรับฉัน
somethingSomething
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.