bash คำสั่งหลายบรรทัดพร้อมกับข้อคิดเห็นหลังจากอักขระต่อเนื่อง


29

พิจารณา

echo \ # this is a comment
foo

สิ่งนี้ให้:

$ sh foo.sh
 # this is a comment
foo.sh: line 2: foo: command not found

หลังจากค้นหาบนเว็บฉันพบวิธีแก้ปัญหาโดย DigitalRossใน Stack Overflow ของเว็บไซต์น้อง ดังนั้นเราสามารถทำได้

echo `: this is a comment` \
foo

หรืออีกวิธีหนึ่ง

echo $(: this is a comment) \
foo

อย่างไรก็ตาม DigitalRoss ไม่ได้อธิบายว่าทำไมโซลูชันเหล่านี้จึงทำงาน ฉันขอขอบคุณคำอธิบาย เขาตอบด้วยความคิดเห็น:

เคยมีgotoคำสั่งเปลือกซึ่งแยกเป็นป้ายระบุ:ที่นี่ gotoจะหายไป แต่คุณยังคงสามารถใช้ : whateverไวยากรณ์ ... :เป็นประเภทของการแสดงความคิดเห็นแจงตอนนี้

แต่ฉันต้องการรายละเอียดเพิ่มเติมและบริบทรวมถึงการอภิปรายเรื่องการพกพา

แน่นอนถ้าใครมีวิธีแก้ปัญหาอื่น ๆ ก็คงจะดีเช่นกัน

ดูคำถามก่อนหน้านี้วิธีแสดงความคิดเห็นคำสั่งหลายบรรทัดในเชลล์สคริปต์ได้อย่างไร .


นำข้อความกลับบ้านจากการสนทนาด้านล่าง `: this is a comment`เป็นเพียงแทนคำสั่ง การส่งออกของอะไรและที่ได้รับการวางในสถานที่ของ: this is a comment`: this is a comment`

ทางเลือกที่ดีกว่าคือ:

echo `# this is a comment` \
foo

คำตอบ:


25

ความคิดเห็นสิ้นสุดที่บรรทัดแรกแรก (ดูกฎการรู้จำเชลล์โทเค็น 10 ) โดยไม่อนุญาตให้มีบรรทัดต่อเนื่องดังนั้นรหัสนี้จึงมีfooบรรทัดคำสั่งแยกต่างหาก:

echo # this is a comment \
foo

สำหรับข้อเสนอแรกของคุณแบ็กสแลชไม่ได้ตามด้วยการขึ้นบรรทัดใหม่คุณเพียงแค่ระบุพื้นที่: มันเทียบเท่ากับ

echo ' # this is a comment'
foo

$(: this is a comment): this is a commentทดแทนการส่งออกของคำสั่ง หากเอาต์พุตของคำสั่งนั้นว่างเปล่านี่เป็นวิธีที่ทำให้เกิดความสับสนอย่างมากในการแทรกความคิดเห็นในบรรทัดกลาง

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

# Sample code to compress files that don't look compressed
case "$1" in
  *.gz|*.tgz|*.bz2|*.zip|*.jar|*.od?) :;; # the file is already compressed
  *) bzip2 -9 "$1";;
esac

กรณีการใช้งานอื่นเป็นสำนวนสำหรับการตั้งค่าตัวแปรหากยังไม่ได้ตั้งค่า

: "${foo:=default value}"

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


โอเคฉันเข้าใจแล้ว มีวิธีใดวิธีหนึ่งที่ดีกว่าในการแทรกความคิดเห็นในบริบทนี้ที่คุณรับรู้
Faheem Mitha

3
@FaheemMitha ตามที่แนะนำในเธรดที่คุณอ้างถึง: แบ่งคำสั่งของคุณเป็นกลุ่มที่จัดการได้และแสดงความคิดเห็นแต่ละอัน หากคำสั่งของคุณซับซ้อนมากจนต้องการความคิดเห็นตรงกลางถึงเวลาที่ต้องทำให้มันง่ายขึ้น!
Gilles 'หยุดชั่วร้าย'

1
คำสั่งที่สงสัยมีข้อโต้แย้งมากมาย ... มันแปลงไฟล์วิดีโอเป็นไฟล์เดียว ฉันไม่เห็นวิธีที่จะทำให้มันง่ายขึ้น อาจสร้างรายการบางประเภทและส่งผ่านเป็นอาร์กิวเมนต์หรือไม่ ฉันเดาว่าอาจเป็นคำถามอื่น
Faheem Mitha

@FaheemMitha ตัวอย่าง: make_FINDสคริปต์ quickie ที่สร้างรายการอาร์กิวเมนต์จำนวนfindมาก ที่นี่แรงบันดาลใจสำหรับการสร้างชิ้นโดยชิ้นคือแต่ละชิ้นมาจากร่างกายของห่วง แต่สไตล์เดียวกันช่วยให้แสดงความคิดเห็นในแต่ละก้อน
Gilles 'หยุดชั่วร้าย'

1
ขอบคุณสำหรับตัวอย่าง ตัวอย่างของฉันนั้นเป็นเพียงรายชื่อยาว ๆ ที่ให้ไว้เป็นอาร์กิวเมนต์ของคำสั่ง ฉันต้องการความคิดเห็นที่แนบมากับชื่อแต่ละชื่อเพราะนั่นเป็นวิธีที่ง่ายที่สุดสำหรับฉันในการรักษาบริบท ฉันไม่เห็นวิธีที่ชัดเจนในการแยกคำสั่งออกเป็นชิ้น ๆ และถ้าฉันทำมันอาจทำให้ใช้งานได้นานขึ้นและนานพอแล้ว
Faheem Mitha

6

คุณสามารถทำได้โดยใช้ Bash arrays เช่น

#!/bin/bash
CMD=(
  echo  # this is a comment
  foo
  )

"${CMD[@]}"

สิ่งนี้จะกำหนดอาเร$CMDย์แล้วขยายออก เมื่อขยายบรรทัดผลลัพธ์จะถูกประเมินดังนั้นในกรณีนี้echo fooจะถูกดำเนินการ

ข้อความระหว่าง(และ)กำหนดอาร์เรย์และอยู่ภายใต้ไวยากรณ์ทุบตีตามปกติดังนั้นทุกอย่างในบรรทัดหลังจาก#จะถูกละเว้น

หมายเหตุเกี่ยวกับการรักษาช่องว่างที่ยกมา

${CMD[@]}ขยายเป็นสตริงเดี่ยวซึ่งเป็นการต่อกันขององค์ประกอบทั้งหมดคั่นด้วยช่องว่าง เมื่อขยายแล้ว Bash จะวิเคราะห์สตริงเป็นโทเค็นในลักษณะปกติ (cf $ IFS ) ซึ่งมักจะไม่ใช่สิ่งที่เราต้องการ

ในทางตรงกันข้ามถ้าการขยายตัวถูกห่อด้วยเครื่องหมายคำพูดคู่นั่นคือ"${CMD[@]}"แต่ละองค์ประกอบในอาร์เรย์จะถูกเก็บรักษาไว้ พิจารณาความแตกต่างระหว่างและhello world second item"hello world" "second item"

ตัวอย่างที่แสดงให้เห็น:

# LIST=("hello world" "second item")

# for ITEM in ${LIST[@]}; do echo $ITEM; done
hello
world
second
item

# for ITEM in "${LIST[@]}"; do echo $ITEM; done
hello world
second item

ขอบคุณสำหรับคำตอบ @RobM ดังนั้นข้อเสนอแนะของคุณคือรวมข้อคิดเห็น / ข้อมูลเมตาเกี่ยวกับรายการในรายการในอาร์เรย์ bash เอง คำถามนี้อาจมีประโยชน์มากกว่าหากฉันรวมตัวอย่างของคำสั่งที่ฉันพยายามใช้ ฉันไม่รู้ว่าทำไมฉันไม่
Faheem Mitha

เฮ้ปรากฎว่าฉันไม่ได้อ่านคำถามของคุณอย่างระมัดระวัง คิดว่าคุณกำลังถามคำถามที่คุณเชื่อมโยง อุ่ย :)
RobM

${CMD[@]}ไม่ขยายเป็นสตริงเดี่ยว - มันจะขยายไปยังสตริงจำนวนมาก: ไม่เพียง แต่แยกสำหรับแต่ละองค์ประกอบของอาร์เรย์ แต่ยังอยู่ในช่องว่างในแต่ละองค์ประกอบ (เช่น: ไร้ประโยชน์อย่างสมบูรณ์)
Robert Siemer

4

$(: comment)ไม่ได้ทำ นั่นไม่ใช่ความคิดเห็น - นั่นเป็นเชลล์ย่อย - อีกกระบวนการเชลล์ใหม่สำหรับเชลล์ส่วนใหญ่ เป้าหมายของคุณคือลดการป้อนข้อมูลของคุณให้น้อยลงไม่มากไปกว่านี้ซึ่งเป็นสิ่งที่ต้องทำแม้ว่าจะไม่มีจุดหมายก็ตาม

คุณสามารถทำแทน ...

printf '<%s>\n' some args here ${-##*"${--

                my long comment block

                }"}  and "more ${-##*"${--

                and another one in the
                middle of the quoted string
                there shouldn\'t b\e any special &
                (character) `echo issues here i hope >&2`
                basically anything that isn\'t a close \}
                $(echo the shell is looking for one >&2)
                }$(echo "}'"\" need backslash escaping >&2
                                )${-##*${--

                nesting is cool though

             }}"}here too"

}'" need backslash escaping
<some>
<args>
<here>
<and>
<more here too>

โดยพื้นฐานแล้วสิ่งที่เกิดขึ้นนั่นคือเปลือกหอยกำลังทำการทดแทน มันทดแทนค่าของพารามิเตอร์เปลือกพิเศษ$-สองครั้งในแต่ละครั้ง มันเป็นสตริงสั้น ๆ แต่มีการตั้งค่าเสมอ - และดังนั้นการทดแทนภายใน - ซึ่งถูกตีความว่าเป็นรูปแบบที่จะตัดจากด้านนอก - ไม่ขยายไปยังเนื้อหาระหว่างวงเล็บเมื่อฉันใช้-แบบฟอร์มการขยาย

ที่นี่:

bash -x <<""
printf %s\\n '${-##*"'${-- a set param doesn\'t expand to this optional text }'"}'

+ printf '%s\n' '${-##*"hxB"}'
${-##*"hxB"}

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

ยังดีกว่า:

COMMENT=
echo      ${COMMENT-"
           this will work the same way
           but the stripping isn\'t
           necessary because, while
           the variable is set, it is also
           empty, and so it will expand to
           its value - which is nothing
           "} this you\'ll see

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