backticks (เช่น `cmd`) ในกระสุน sh ถูกเลิกใช้แล้วหรือยัง?


118

ฉันเคยเห็นความคิดเห็นนี้หลายครั้งใน Unix & Linux เช่นเดียวกับเว็บไซต์อื่น ๆ ที่ใช้วลี "backticks ได้รับการคัดค้าน" ด้วยความเคารพต่อเชลล์เช่น Bash & Zsh

คำสั่งนี้เป็นจริงหรือเท็จ?


ดูทำไมเครื่องหมายอัญประกาศในเชลล์สคริปต์ไม่ได้ช่วยฉันcdไปยังไดเรกทอรีเพื่อดูว่าเหตุใด$(...)สัญกรณ์ใช้งานง่ายกว่าเครื่องหมายคำพูดซ้อนหลัง
Jonathan Leffler


1
อย่างน้อยหนึ่ง Unix, AIX, มีเอกสารที่ backticks มีความล้าสมัย "แม้ว่า ksh จะยอมรับไวยากรณ์ backquote แต่ก็ถือว่าล้าสมัยโดย X / Open Portability Guide Issue 4 และ POSIX มาตรฐานมาตรฐานเหล่านี้แนะนำให้แอปพลิเคชันแบบพกพาใช้ไวยากรณ์ $ (คำสั่ง)" ibm.com/support/knowledgecenter/ssw_aix_71/com.ibm.aix.osdevice/…
คริสโตเฟอร์

ฉันมีความแตกต่างที่ชัดเจนใน "GNU ทุบตีรุ่น 3.2.57 (1) - ปล่อย (x86_64-apple-darwin14)" ใน mac 10.10: matchingLines=$( grep -n '\$-PARAMETER' ... | ... )ทำงานmatchingLines= backtick the same stuff backtickไม่ทำงานดูเหมือนจะสูญเสียแบ็กสแลชในแบ็กสแลชดอลลาร์ (ไม่ใช่สคริปต์ของฉัน ... )
denis

คำตอบ:


126

มีความหมายที่แตกต่างกันสองอย่างของ "คัดค้าน"

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

- พจนานุกรมฟอร์ดอเมริกันใหม่

โดยคำจำกัดความ backticks นี้ถูกคัดค้าน

สถานะที่เลิกใช้แล้วอาจระบุว่าสถานที่นั้นจะถูกลบในอนาคต

- วิกิพีเดีย

โดยคำจำกัดความ backticks นี้จะไม่คัดค้าน

ยังคงได้รับการสนับสนุน:

การอ้างถึงOpen Group Specification ในภาษาคำสั่งเชลล์โดยเฉพาะส่วน "2.6.3 การทดแทนคำสั่ง" จะเห็นได้ว่าทั้งการทดแทนคำสั่งทั้งสองรูปแบบ backticks ( `..cmd..`) หรือ parens ดอลล่าร์ ( $(..cmd..)) ยังคงได้รับการสนับสนุนตราบเท่าที่ข้อมูลจำเพาะ

สิ่งที่สกัดมา

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

          $(command)

          or (backquoted version):

          `command`

เชลล์จะขยายการทดแทนคำสั่งโดยการดำเนินการคำสั่งในสภาพแวดล้อม subshell (ดูที่ Shell Execution Environment) และแทนที่การแทนที่คำสั่ง (ข้อความของคำสั่งรวมถึงการปิดล้อม$()หรือแบ็กโคต์) ด้วยเอาต์พุตมาตรฐานของคำสั่ง <newline> ตัวอักษรในตอนท้ายของการทดแทน อักขระ <newline> แบบฝังก่อนสิ้นเอาต์พุตจะไม่ถูกลบออก อย่างไรก็ตามอาจถูกใช้เป็นตัวคั่นฟิลด์และตัดออกในระหว่างการแยกฟิลด์ขึ้นอยู่กับค่าของ IFS และการอ้างอิงที่มีผล หากผลลัพธ์มีไบต์เป็นโมฆะพฤติกรรมจะไม่ได้รับการกำหนด

ภายในสไตล์ backquoted ของแทนคำสั่ง<ทับขวา>จะเก็บความหมายที่แท้จริงของมันยกเว้นเมื่อตามด้วย: '$', ' \`' หรือ<ทับขวา> การค้นหา backquote ที่ตรงกันจะต้องเป็นไปตาม backquote ที่ไม่มีการ Escape แรก ในระหว่างการค้นหานี้หากพบ backquote ที่ไม่ได้ใช้ Escape ภายในข้อคิดเห็นเชลล์, here-document, การแทนที่คำสั่งแบบฝังของ$(command)ฟอร์มหรือสตริงที่ยกมาผลลัพธ์ที่ไม่ได้กำหนดจะเกิดขึ้น สตริงที่มีเครื่องหมายคำพูดเดี่ยวหรือเครื่องหมายคำพูดคู่ที่เริ่มต้น แต่ไม่สิ้นสุดภายใน`...`ลำดับ "" จะสร้างผลลัพธ์ที่ไม่ได้กำหนด

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

แล้วทำไมทุกคนถึงพูดว่า backticks นั้นเลิกใช้แล้ว

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

  • BashFAQ # 082 - ทำไม $ (... ) ถึงชอบมากกว่า '... ' (backticks)

    สิ่งที่สกัดมา

    `...`เป็นไวยากรณ์ดั้งเดิมที่จำเป็นโดย bourne-shell ที่เก่าแก่ที่สุดและไม่รองรับ POSIX มีหลายเหตุผลที่จะชอบ$(...)ไวยากรณ์:

    ...

  • Bash Hackers Wiki - ไวยากรณ์ที่เลิกใช้แล้วและเลิกใช้แล้ว

    สิ่งที่สกัดมา

    นี่คือรูปแบบที่เข้ากันได้บอร์นเก่าแทนคำสั่ง ทั้งสอง`COMMANDS`และ$(COMMANDS)ไวยากรณ์ที่ระบุโดย POSIX แต่หลังเป็นที่ต้องการอย่างมากถึงแม้ว่าอดีตยังคงเป็นที่แพร่หลายมากในสคริปต์ การแทนที่คำสั่งสไตล์ใหม่มีการใช้งานอย่างกว้างขวางในทุก ๆ เชลล์ที่ทันสมัย ​​(และบางอัน) เหตุผลเดียวในการใช้ backticks สำหรับความเข้ากันได้กับเชลล์เป้าหมายจริง (เช่น Heirloom) การทดแทนคำสั่ง Backtick ต้องการการหลบหลีกพิเศษเมื่อซ้อนกันและตัวอย่างที่พบในไวด์จะถูกยกมาอย่างไม่เหมาะสมบ่อยกว่าไม่ ดู: ทำไมถึงต้องการ $ (... ) มากกว่า `... '(backticks) .

  • เหตุผลมาตรฐาน POSIX

    สิ่งที่สกัดมา

    เนื่องจากพฤติกรรมที่ไม่สอดคล้องกันเหล่านี้จึงไม่แนะนำให้ใช้ความหลากหลายของการทดแทนคำสั่ง backquote สำหรับแอปพลิเคชันใหม่ที่แทนที่การแทนที่คำสั่งซ้อนหรือพยายามฝังสคริปต์ที่ซับซ้อน

หมายเหตุ:ข้อความที่ตัดตอนมาที่สามนี้ (ด้านบน) แสดงต่อไปในหลาย ๆ สถานการณ์ที่ backticks ใช้งานไม่ได้ แต่วิธี parens dollar ที่ใหม่กว่านั้นเริ่มต้นด้วยย่อหน้าต่อไปนี้:

นอกจากนี้ไวยากรณ์ backquote มีข้อ จำกัด ทางประวัติศาสตร์เกี่ยวกับเนื้อหาของคำสั่งฝังตัว แม้ว่ารูปแบบ "$ ()" ที่ใหม่กว่าสามารถประมวลผลสคริปต์ฝังตัวที่ถูกต้องชนิดใดรูปแบบ backquote ไม่สามารถจัดการกับสคริปต์ที่ถูกต้องซึ่งรวมถึง backquotes

หากคุณอ่านต่อในส่วนนั้นความล้มเหลวจะถูกเน้นให้เห็นว่าพวกเขาจะล้มเหลวในการใช้ backticks แต่ทำงานโดยใช้สัญลักษณ์ดอลลาร์แบบใหม่

สรุปผลการวิจัย

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

หลังจากอ่านทั้งหมดนี้คุณควรจะมีเวลาห่างที่คุณควรอย่างยิ่งที่จะใช้เงินดอลลาร์ parens เว้นแต่คุณโดยเฉพาะต้องเข้ากันได้กับจริงเดิมไม่ใช่ POSIX เปลือกบอร์น


26
โดยความหมายส่วนใหญ่ของเลิกฉันฉัน (และคุณ) จะบอกว่า backticks จะคัดค้าน ส่วนใหญ่เป็นคำถามคำศัพท์
Stéphane Chazelas

4
@StephaneChazelas - เห็นด้วย! ฉันจะบอก ppl ต่อไปว่าพวกเขาเลิกใช้แล้ว แต่ backticks ยังไม่ได้ "เลิก" อย่างเป็นทางการในแง่ที่ว่าพวกเขากำลังจะถูกลบออกจากฐานรหัสของเชลล์ใด ๆ ในอนาคตอันใกล้ อย่างน้อยฉันก็ไม่รู้
slm

3
การตีความของฉันคือ backquotes ได้รับการสนับสนุนอย่างหมดจดเพราะมันยึดติดอยู่ในรหัสที่มีอยู่เกินกว่าที่จะคัดค้านอย่างเป็นทางการ ฉันไม่เคยได้ยินข้อโต้แย้งเกี่ยวกับการใช้รหัสเหล่านี้ต่อไป
chepner

3
@slm ใช่ฉันคิดว่าคุณทำได้ - ฉันถูกดึงออกไปและไม่ได้สังเกต เกือบจะไม่มีเหตุผลที่จะใช้สิ่งเหล่านี้ยกเว้นว่ามันจะเป็นเพียงเล็กน้อยที่สะอาดกว่าเมื่อฝังชั้น subshells ดังนั้น$( cmd `cmd`)จะยุ่งน้อยกว่าเล็กน้อย$( cmd $(cmd))- อ่านง่ายกว่า ฉันเพิ่งพิจารณาคุณสมบัติที่เลิกใช้แล้วในซอฟต์แวร์เพื่อเป็นเครื่องหมายอย่างเป็นทางการสำหรับการลบโดยอัปสตรีม - และฉันไม่เคยได้ยินอะไรแบบนั้นมาก่อน ฉันไม่สนใจ - ไม่มีความรักสำหรับหลุมฝังศพ
mikeserv

3
คุณอาจต้องการเพิ่มเครื่องหมายคำพูดต่อไปนี้จากเหตุผลมาตรฐาน POSIX : เนื่องจากพฤติกรรมที่ไม่สอดคล้องกันเหล่านี้จึงไม่แนะนำให้ใช้การทดแทนหลากหลายคำสั่ง backquote สำหรับแอปพลิเคชันใหม่ที่แทนคำสั่งซ้อนหรือพยายามฝังสคริปต์ที่ซับซ้อน แม้ว่านี่จะไม่ใช่การคัดค้านอย่างเป็นทางการเนื่องจากส่วนเหตุผลเป็นข้อมูลและไม่เป็นบรรทัดฐาน แต่ก็แนะนำว่าควรหลีกเลี่ยงการใช้ backticks ต่อไป
jw013

15

มันไม่ได้คัดค้าน แต่ backticks ( `...`) เป็นไวยากรณ์ดั้งเดิมที่จำเป็นสำหรับ bourne-shell ที่ไม่รองรับ POSIX ที่เก่าแก่ที่สุดและ$(...)POSIX และเป็นที่นิยมมากกว่าด้วยเหตุผลหลายประการ:

  • แบ็กสแลช ( \) ภายใน backticks ได้รับการจัดการในลักษณะที่ไม่ชัดเจน:

    $ echo "`echo \\a`" "$(echo \\a)"
    a \a
    $ echo "`echo \\\\a`" "$(echo \\\\a)"
    \a \\a
    # Note that this is true for *single quotes* too!
    $ foo=`echo '\\'`; bar=$(echo '\\'); echo "foo is $foo, bar is $bar" 
    foo is \, bar is \\
  • ข้อความที่ซ้อนกันภายใน$()มีความสะดวกมากขึ้น:

    echo "x is $(sed ... <<<"$y")"

    แทน:

    echo "x is `sed ... <<<\"$y\"`"

    หรือเขียนสิ่งที่ชอบ:

    IPs_inna_string=`awk "/\`cat /etc/myname\`/"'{print $1}' /etc/hosts`

    เพราะ$()ใช้บริบทใหม่ทั้งหมดสำหรับการอ้างอิง

    ซึ่งไม่สามารถพกพาได้เนื่องจากกระสุน Bourne และ Korn จะต้องใช้แบ็กสแลชเหล่านี้ในขณะที่ Bash และ Dash จะไม่ทำงาน

  • ไวยากรณ์สำหรับการแทนที่คำสั่งซ้อนได้ง่ายขึ้น:

    x=$(grep "$(dirname "$path")" file)

    กว่า:

    x=`grep "\`dirname \"$path\"\`" file`

    เนื่องจาก$()บังคับใช้บริบทใหม่ทั้งหมดสำหรับการอ้างอิงดังนั้นการทดแทนคำสั่งแต่ละรายการจะได้รับการคุ้มครองและสามารถปฏิบัติได้ด้วยตนเองโดยไม่ต้องกังวลเป็นพิเศษเกี่ยวกับการอ้างอิงและการหลบหนี เมื่อใช้ backticks มันจะได้รับ uglier และ uglier หลังจากระดับที่สองขึ้นไป

    อีกไม่กี่ตัวอย่าง:

    echo `echo `ls``      # INCORRECT
    echo `echo \`ls\``    # CORRECT
    echo $(echo $(ls))    # CORRECT
  • มันแก้ปัญหาพฤติกรรมที่ไม่สอดคล้องกันเมื่อใช้ backquotes:

    • echo '\$x' เอาท์พุท \$x
    • echo `echo '\$x'` เอาท์พุท $x
    • echo $(echo '\$x') เอาท์พุท \$x
  • ไวยากรณ์ Backticks มีข้อ จำกัด ทางประวัติศาสตร์เกี่ยวกับเนื้อหาของคำสั่งแบบฝังและไม่สามารถจัดการกับสคริปต์ที่ถูกต้องซึ่งรวมถึง backquotes ในขณะที่$()แบบฟอร์มที่ใหม่กว่าสามารถประมวลผลสคริปต์ฝังตัวชนิดใดก็ได้ที่ถูกต้อง

    ตัวอย่างเช่นสคริปต์ฝังตัวที่ถูกต้องมิฉะนั้นจะไม่ทำงานในคอลัมน์ด้านซ้าย แต่ทำงานบนIEEEด้านขวา:

    echo `                         echo $(
    cat <<\eof                     cat <<\eof
    a here-doc with `              a here-doc with )
    eof                            eof
    `                              )
    
    
    echo `                         echo $(
    echo abc # a comment with `    echo abc # a comment with )
    `                              )
    
    
    echo `                         echo $(
    echo '`'                       echo ')'
    `                              )

ดังนั้นไวยากรณ์สำหรับการทดแทนคำสั่ง$ -prefixed ควรเป็นวิธีที่ต้องการเนื่องจากชัดเจนด้วยไวยากรณ์ที่สะอาด (ปรับปรุงความสามารถในการอ่านของมนุษย์และเครื่องจักร) มันสามารถซ้อนกันได้และใช้งานง่ายการแยกวิเคราะห์ภายในจะแยกจากกันและมีความสอดคล้องมากกว่า การขยายอื่น ๆ ทั้งหมดที่แยกวิเคราะห์จากภายในเครื่องหมายคำพูดคู่) ที่ backticks เป็นข้อยกเว้นเพียงอย่างเดียวและตัวละครนั้นพรางตัวได้ง่ายเมื่ออยู่ติดกันทำให้อ่านยากยิ่งขึ้นโดยเฉพาะอย่างยิ่งกับตัวอักษรขนาดเล็กหรือผิดปกติ`"

ที่มา: ทำไมจึงเป็น$(...)ที่ต้องการมากกว่า`...`(backticks) ที่ BashFAQ

ดูสิ่งนี้ด้วย:

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