คุณจะใช้สายต่อเนื่อง bash ได้อย่างไร?
ฉันรู้ว่าคุณสามารถทำได้:
echo "continuation \
lines"
>continuation lines
อย่างไรก็ตามหากคุณมีรหัสที่เยื้องมันก็ไม่ได้ผลดีนัก:
echo "continuation \
lines"
>continuation lines
คุณจะใช้สายต่อเนื่อง bash ได้อย่างไร?
ฉันรู้ว่าคุณสามารถทำได้:
echo "continuation \
lines"
>continuation lines
อย่างไรก็ตามหากคุณมีรหัสที่เยื้องมันก็ไม่ได้ผลดีนัก:
echo "continuation \
lines"
>continuation lines
คำตอบ:
นี่คือสิ่งที่คุณอาจต้องการ
$ echo "continuation"\
> "lines"
continuation lines
หากสิ่งนี้สร้างสองอาร์กิวเมนต์เพื่อ echo และคุณต้องการเพียงหนึ่งแล้วลองดูที่การต่อสตริง ในทุบตีวางสองสายติดกันเรียงกัน:
$ echo "continuation""lines"
continuationlines
ดังนั้นเส้นต่อเนื่องที่ไม่มีการเยื้องจึงเป็นวิธีหนึ่งในการแยกสตริง:
$ echo "continuation"\
> "lines"
continuationlines
แต่เมื่อใช้การเยื้อง:
$ echo "continuation"\
> "lines"
continuation lines
คุณจะได้รับสองข้อโต้แย้งเพราะนี่จะไม่เป็นการต่อกันอีกต่อไป
หากคุณต้องการสตริงเดี่ยวที่ข้ามเส้นในขณะที่เยื้อง แต่ไม่ได้รับช่องว่างทั้งหมดวิธีหนึ่งที่คุณสามารถลองทำได้คือการทิ้งบรรทัดต่อเนื่องและใช้ตัวแปร:
$ a="continuation"
$ b="lines"
$ echo $a$b
continuationlines
สิ่งนี้จะช่วยให้คุณมีรหัสที่เยื้องอย่างหมดจดด้วยค่าใช้จ่ายของตัวแปรเพิ่มเติม หากคุณทำให้ตัวแปรในตัวเครื่องไม่ควรเลวร้ายเกินไป
s="string no. 1" s+="string no. 2" s+=" string no. 3" echo "$s"
ที่นี่เอกสารที่มีตัว<<-HERE
ยุติทำงานได้ดีสำหรับสตริงข้อความแบบหลายบรรทัดที่เยื้อง มันจะลบแท็บนำออกจากเอกสาร here (ตัวยกเลิกสายจะยังคงอยู่แม้ว่า)
cat <<-____HERE
continuation
lines
____HERE
ดูเพิ่มเติมที่http://ss64.com/bash/syntax-here.html
หากคุณต้องการรักษาบางส่วน แต่ไม่ทั้งหมดนำช่องว่างคุณอาจใช้สิ่งที่ชอบ
sed 's/^ //' <<____HERE
This has four leading spaces.
Two of them will be removed by sed.
____HERE
หรืออาจใช้tr
เพื่อกำจัดบรรทัดใหม่:
tr -d '\012' <<-____
continuation
lines
____
(บรรทัดที่สองมีแท็บและเว้นวรรคด้านหน้าแท็บจะถูกลบโดยตัวดำเนินการเส้นประก่อนเทอร์มินัล heredoc ในขณะที่พื้นที่จะถูกเก็บรักษาไว้)
สำหรับการตัดสตริงที่ซับซ้อนที่มีความยาวมากกว่าหลายบรรทัดฉันชอบprintf
:
printf '%s' \
"This will all be printed on a " \
"single line (because the format string " \
"doesn't specify any newline)"
นอกจากนี้ยังทำงานได้ดีในบริบทที่คุณต้องการฝังชิ้นขี้ปะติ๋วของเชลล์สคริปต์ในภาษาอื่นที่ไวยากรณ์ภาษาโฮสต์จะไม่ยอมให้คุณใช้เอกสารที่นี่เช่นในหรือMakefile
Dockerfile
printf '%s\n' >./myscript \
'#!/bin/sh` \
"echo \"G'day, World\"" \
'date +%F\ %T' && \
chmod a+x ./myscript && \
./myscript
printf
ตัวอย่างแรกด้วยตอนนี้)
คุณสามารถใช้bash arrays
$ str_array=("continuation"
"lines")
แล้วก็
$ echo "${str_array[*]}"
continuation lines
มีพื้นที่เพิ่มเติมเนื่องจาก (หลังจาก bash manual):
ถ้าคำนี้ถูกยกมาสองคำให้
${name[*]}
ขยายเป็นคำเดียวโดยมีค่าของสมาชิกอาเรย์แต่ละตัวคั่นด้วยอักขระตัวแรกของตัวแปร IFS
ดังนั้นตั้งIFS=''
เพื่อกำจัดพื้นที่พิเศษ
$ IFS=''
$ echo "${str_array[*]}"
continuationlines
ในบางสถานการณ์ที่ใช้ความสามารถในการต่อข้อมูลของ Bash อาจเหมาะสม
temp='this string is very long '
temp+='so I will separate it onto multiple lines'
echo $temp
this string is very long so I will separate it onto multiple lines
ชื่อ = [ค่า] ...
... ในบริบทที่คำสั่งการมอบหมายกำลังกำหนดค่าให้กับตัวแปรเชลล์หรือดัชนีอาร์เรย์คุณสามารถใช้เครื่องหมาย + = เพื่อผนวกหรือเพิ่มค่าก่อนหน้าของตัวแปร เมื่อ + = ถูกนำไปใช้กับตัวแปรที่มีการตั้งค่าแอตทริบิวต์จำนวนเต็มค่าจะถูกประเมินเป็นนิพจน์ทางคณิตศาสตร์และเพิ่มลงในค่าปัจจุบันของตัวแปรซึ่งจะถูกประเมินเช่นกัน เมื่อ + = ถูกนำไปใช้กับตัวแปรอาร์เรย์โดยใช้การมอบหมายแบบผสม (ดูอาร์เรย์ด้านล่าง) ค่าของตัวแปรจะไม่ถูกยกเลิก (เช่นเมื่อใช้ =) และค่าใหม่จะถูกผนวกเข้ากับอาร์เรย์ที่เริ่มต้นที่หนึ่งที่สูงกว่าดัชนีสูงสุดของอาร์เรย์ (สำหรับอาร์เรย์ที่ทำดัชนี) หรือเพิ่มเป็นคู่ของคีย์ - ค่าเพิ่มเติมในอาเรย์แบบเชื่อมโยง เมื่อนำไปใช้กับตัวแปรที่มีค่าสตริงค่าจะถูกขยายและผนวกเข้ากับค่าของตัวแปร
ฉันเจอสถานการณ์ที่ฉันต้องส่งข้อความยาวเป็นส่วนหนึ่งของการโต้แย้งคำสั่งและต้องปฏิบัติตามข้อ จำกัด ความยาวบรรทัด คำสั่งมีลักษณะดังนี้:
somecommand --message="I am a long message" args
วิธีที่ฉันแก้ไขนี้คือการย้ายข้อความออกเป็นเอกสารที่นี่ (เช่น @tripleee แนะนำ) แต่เอกสารที่นี่กลายเป็น stdin ดังนั้นจึงจำเป็นต้องอ่านอีกครั้งฉันไปด้วยวิธีการด้านล่าง:
message=$(
tr "\n" " " <<- END
This is a
long message
END
)
somecommand --message="$message" args
นี่เป็นข้อดีที่$message
สามารถใช้เป็นค่าคงที่สตริงได้โดยไม่ต้องมีช่องว่างหรือตัวแบ่งบรรทัด
โปรดทราบว่าบรรทัดข้อความจริงดังกล่าวข้างต้นจะถูกนำหน้าด้วยtab
อักขระแต่ละตัวซึ่งจะถูกแยกโดยเอกสารที่นี่เอง (เนื่องจากการใช้งาน<<-
) ยังคงมีตัวแบ่งบรรทัดในตอนท้ายซึ่งจะถูกแทนที่dd
ด้วยช่องว่าง
โปรดทราบว่าหากคุณไม่ลบบรรทัดใหม่พวกเขาจะปรากฏขึ้นตามเวลาที่"$message"
ถูกขยาย ในบางกรณีคุณอาจสามารถแก้ไขปัญหาได้โดยลบเครื่องหมายคำพูดคู่ล้อมรอบ$message
แต่ข้อความจะไม่เป็นอาร์กิวเมนต์เดี่ยวอีกต่อไป
การต่อเนื่องสายสามารถทำได้ด้วยการใช้ไวยากรณ์อย่างชาญฉลาด
ในกรณีของecho
:
# echo '-n' flag prevents trailing <CR>
echo -n "This is my one-line statement" ;
echo -n " that I would like to make."
This is my one-line statement that I would like to make.
ในกรณีของ vars:
outp="This is my one-line statement" ;
outp+=" that I would like to make." ;
echo -n "${outp}"
This is my one-line statement that I would like to make.
วิธีการอื่นในกรณีของ vars:
outp="This is my one-line statement" ;
outp="${outp} that I would like to make." ;
echo -n "${outp}"
This is my one-line statement that I would like to make.
Voila!
คุณสามารถแยกมันออกเป็นบรรทัดใหม่ได้โดยไม่ต้องใช้แบ็กสแลชตามที่ต้องการในการเยื้องดังนี้
ตัวอย่าง:
echo "continuation
of
lines" | tr '\n' ' '
หรือถ้ามันเป็นตัวแปรบรรทัดใหม่นิยามตัวแปรจะถูกแปลงเป็นช่องว่างโดยอัตโนมัติ ดังนั้นแถบของช่องว่างพิเศษเฉพาะถ้ามี
x="continuation
of multiple
lines"
y="red|blue|
green|yellow"
echo $x # This will do as the converted space actually is meaningful
echo $y | tr -d ' ' # Stripping of space may be preferable in this case
นี่ไม่ใช่สิ่งที่ผู้ใช้ถามอย่างแน่นอน แต่อีกวิธีในการสร้างสตริงที่ยาวซึ่งครอบคลุมหลายบรรทัดคือการสร้างมันขึ้นทีละน้อยเช่น:
$ greeting="Hello"
$ greeting="$greeting, World"
$ echo $greeting
Hello, World
เห็นได้ชัดว่าในกรณีนี้มันจะง่ายกว่าในการสร้างแบบครั้งเดียว แต่สไตล์นี้อาจมีน้ำหนักเบาและเข้าใจได้ง่ายเมื่อจัดการกับสตริงที่ยาวขึ้น
อย่างไรก็ตามหากคุณมีรหัสที่เยื้องมันก็ไม่ได้ผลดีนัก:
echo "continuation \ lines" >continuation lines
ลองด้วยคำพูดเดียวและเชื่อมสตริง:
echo 'continuation' \
'lines'
>continuation lines
หมายเหตุ: การต่อข้อมูลรวมถึงช่องว่าง
echo
ถ้าคุณมีx=
คุณจะได้รับข้อผิดพลาด: lines: command not found
.
ขึ้นอยู่กับประเภทของความเสี่ยงที่คุณจะยอมรับและความรู้และความน่าเชื่อถือของข้อมูลคุณสามารถใช้การแก้ไขตัวแปรแบบง่าย ๆ ได้
$: x="
this
is
variably indented
stuff
"
$: echo "$x" # preserves the newlines and spacing
this
is
variably indented
stuff
$: echo $x # no quotes, stacks it "neatly" with minimal spacing
this is variably indented stuff
สิ่งนี้อาจไม่ตอบคำถามของคุณจริงๆ แต่คุณอาจพบว่ามีประโยชน์
คำสั่งแรกสร้างสคริปต์ที่แสดงโดยคำสั่งที่สอง
คำสั่งที่สามทำให้สคริปต์นั้นทำงานได้
คำสั่งที่สี่ให้ตัวอย่างการใช้งาน
john@malkovich:~/tmp/so$ echo $'#!/usr/bin/env python\nimport textwrap, sys\n\ndef bash_dedent(text):\n """Dedent all but the first line in the passed `text`."""\n try:\n first, rest = text.split("\\n", 1)\n return "\\n".join([first, textwrap.dedent(rest)])\n except ValueError:\n return text # single-line string\n\nprint bash_dedent(sys.argv[1])' > bash_dedent
john@malkovich:~/tmp/so$ cat bash_dedent
#!/usr/bin/env python
import textwrap, sys
def bash_dedent(text):
"""Dedent all but the first line in the passed `text`."""
try:
first, rest = text.split("\n", 1)
return "\n".join([first, textwrap.dedent(rest)])
except ValueError:
return text # single-line string
print bash_dedent(sys.argv[1])
john@malkovich:~/tmp/so$ chmod a+x bash_dedent
john@malkovich:~/tmp/so$ echo "$(./bash_dedent "first line
> second line
> third line")"
first line
second line
third line
โปรดทราบว่าหากคุณต้องการใช้สคริปต์นี้จริง ๆ แล้วการย้ายสคริปต์ที่เรียกใช้งานได้~/bin
นั้นเหมาะสมกว่าเพื่อให้มันอยู่ในเส้นทางของคุณ
ตรวจสอบการอ้างอิงหลามสำหรับรายละเอียดเกี่ยวกับวิธีการtextwrap.dedent
ทำงาน
หากการใช้งาน$'...'
หรือ"$(...)"
สร้างความสับสนให้กับคุณให้ถามคำถามอื่น (หนึ่งข้อต่อการสร้าง) หากยังไม่ได้สร้างขึ้น มันอาจจะดีที่จะให้ลิงค์ไปยังคำถามที่คุณพบ / ถามเพื่อให้คนอื่นจะมีการอ้างอิงที่เชื่อมโยง