Có backticks (tức là `cmd`) trong * sh shell bị phản đối không?


118

Tôi đã thấy nhận xét này nhiều lần trên Unix & Linux cũng như trên các trang web khác sử dụng cụm từ "backticks đã bị phản đối", liên quan đến các shell như Bash & Zsh.

Là tuyên bố này đúng hay sai?


Xem lý do tại sao không quay lại dấu ngoặc kép trong tập lệnh shell giúp tôi cdđến một thư mục để biết ví dụ về lý do tại sao $(...)ký hiệu dễ sử dụng hơn dấu ngoặc kép lồng nhau.
Jonathan Leffler


1
Ít nhất một Unix, AIX, đã ghi nhận rằng backticks đã lỗi thời . "Mặc dù cú pháp backquote được ksh chấp nhận, nhưng nó bị coi là lỗi thời bởi các tiêu chuẩn X / Open Port Guide Guide 4 và POSIX. Các tiêu chuẩn này khuyến nghị các ứng dụng di động sử dụng cú pháp $ (lệnh)." ibm.com/support/ledgeledgecenter/ssw_aix_71/com.ibm.aix.osdevice/ trộm
Christopher

Tôi có một sự khác biệt nhất định trong "GNU bash, phiên bản 3.2.57 (1) -release (x86_64-apple-darwin14)" trên mac 10.10: matchingLines=$( grep -n '\$-PARAMETER' ... | ... )hoạt động, matchingLines= backtick the same stuff backtickkhông hoạt động - dường như mất dấu gạch chéo ngược trong dấu gạch chéo ngược. (Đây không phải là kịch bản của tôi ...)
denis

Câu trả lời:


126

Có hai ý nghĩa khác nhau của "không dùng nữa".

bị phản đối: (chủ yếu là một tính năng phần mềm) có thể sử dụng được nhưng được coi là lỗi thời và tốt nhất nên tránh, thường là do đã được thay thế.

Từ điển Oxford American Oxford

Theo định nghĩa này, backticks không được chấp nhận.

Trạng thái không dùng nữa cũng có thể cho biết tính năng này sẽ bị xóa trong tương lai.

- Wikipedia

Theo định nghĩa này, backticks không được phản đối.

Vẫn được hỗ trợ:

Trích dẫn Đặc tả nhóm mở trên Ngôn ngữ lệnh Shell , cụ thể là phần "2.6.3 Thay thế lệnh", có thể thấy rằng cả hai hình thức thay thế lệnh, backticks ( `..cmd..`) hoặc đô la parens ( $(..cmd..)) vẫn được hỗ trợ trong trường hợp thông số kỹ thuật.

đoạn trích

Thay thế lệnh cho phép đầu ra của một lệnh được thay thế thay cho tên lệnh. Thay thế lệnh sẽ xảy ra khi lệnh được bao quanh như sau:

          $(command)

          or (backquoted version):

          `command`

Shell sẽ mở rộng thay thế lệnh bằng cách thực hiện lệnh trong môi trường lớp con (xem Môi trường thực thi Shell) và thay thế lệnh thay thế (văn bản lệnh cộng với bao vây $()hoặc backquote) bằng đầu ra tiêu chuẩn của lệnh, loại bỏ các chuỗi của một hoặc nhiều ký tự <newline> ở cuối thay thế. Các ký tự <newline> đã nhúng trước khi kết thúc đầu ra sẽ không bị xóa; tuy nhiên, chúng có thể được coi là các dấu phân cách trường và bị loại bỏ trong quá trình tách trường, tùy thuộc vào giá trị của IFS và trích dẫn có hiệu lực. Nếu đầu ra chứa bất kỳ byte rỗng nào, hành vi không được chỉ định.

Trong kiểu thay thế lệnh được trích dẫn ngược , <backslash> sẽ giữ nguyên nghĩa đen của nó, ngoại trừ khi được theo sau: '$', ' \`' hoặc <backslash> . Việc tìm kiếm backquote phù hợp sẽ được thỏa mãn bởi backquote không thoát được trích dẫn đầu tiên; trong quá trình tìm kiếm này, nếu gặp phải một backquote không thoát trong một bình luận shell, tài liệu ở đây, một sự thay thế lệnh nhúng của $(command)biểu mẫu hoặc một chuỗi trích dẫn, kết quả không xác định xảy ra. Một chuỗi trích dẫn đơn hoặc trích dẫn kép bắt đầu, nhưng không kết thúc, trong `...`chuỗi "" tạo ra kết quả không xác định.

Với $(command)biểu mẫu, tất cả các ký tự theo dấu ngoặc đơn mở cho dấu ngoặc đơn đóng phù hợp sẽ tạo thành lệnh. Bất kỳ tập lệnh shell hợp lệ nào cũng có thể được sử dụng cho lệnh, ngoại trừ tập lệnh chỉ bao gồm các hướng dẫn lại tạo ra kết quả không xác định.

Vậy thì tại sao mọi người lại nói rằng backticks đã bị phản đối?

Bởi vì hầu hết các trường hợp sử dụng nên sử dụng hình thức parens đô la thay vì backticks. (Không được dùng theo nghĩa đầu tiên ở trên.) Nhiều trang web có uy tín nhất (bao gồm cả U & L) thường nêu rõ điều này, trong suốt, vì vậy đó là lời khuyên đúng đắn. Lời khuyên này không nên bị nhầm lẫn với một số kế hoạch không tồn tại để loại bỏ hỗ trợ cho backticks khỏi vỏ.

  • BashFAQ # 082 - Tại sao $ (...) được ưa thích hơn `...` (backticks)?

    đoạn trích

    `...`là cú pháp kế thừa được yêu cầu chỉ bởi những bourne-shell cũ nhất không tương thích POSIX. Có một số lý do để luôn thích $(...)cú pháp:

    ...

  • Bash Hackers Wiki - Cú pháp lỗi thời và không dùng nữa

    đoạn trích

    Đây là hình thức tương thích Bourne cũ hơn của sự thay thế lệnh . Cả cú pháp `COMMANDS`$(COMMANDS)cú pháp đều được chỉ định bởi POSIX, nhưng cái sau được ưu tiên rất nhiều , mặc dù cái trước rất tiếc vẫn còn rất phổ biến trong các tập lệnh. Thay thế lệnh kiểu mới được thực hiện rộng rãi bởi mọi shell hiện đại (và sau đó là một số). Lý do duy nhất để sử dụng backticks là vì khả năng tương thích với vỏ Bourne thực sự (như Gia truyền). Thay thế lệnh Backtick yêu cầu thoát đặc biệt khi lồng nhau, và các ví dụ được tìm thấy trong tự nhiên được trích dẫn không chính xác thường xuyên hơn không. Xem: Tại sao $ (...) được ưa thích hơn `...` (backticks)? .

  • Lý do tiêu chuẩn POSIX

    đoạn trích

    Do những hành vi không nhất quán này, sự thay thế lệnh được trích dẫn không được khuyến nghị cho các ứng dụng mới làm tổ thay thế lệnh hoặc cố gắng nhúng các tập lệnh phức tạp.

LƯU Ý: Đoạn trích thứ ba (ở trên) tiếp tục hiển thị một số tình huống trong đó backticks đơn giản là không hoạt động, nhưng phương pháp parens đô la mới hơn thực hiện, bắt đầu với đoạn sau:

Ngoài ra, cú pháp được trích dẫn lại có các hạn chế lịch sử đối với nội dung của lệnh được nhúng. Mặc dù biểu mẫu "$ ()" mới hơn có thể xử lý bất kỳ loại tập lệnh nhúng hợp lệ nào, biểu mẫu được trích dẫn lại có thể xử lý một số tập lệnh hợp lệ bao gồm các câu hỏi ngược.

Nếu bạn tiếp tục đọc phần đó, các thất bại được tô sáng cho thấy họ sẽ thất bại như thế nào khi sử dụng backticks, nhưng hãy thực hiện bằng cách sử dụng ký hiệu parens đô la mới hơn.

Kết luận

Vì vậy, tốt hơn là bạn nên sử dụng đồng đô la thay vì backticks nhưng thực tế bạn không sử dụng thứ gì đó bị "phản đối" về mặt kỹ thuật như trong "điều này sẽ ngừng hoạt động hoàn toàn tại một số điểm theo kế hoạch."

Sau khi đọc tất cả những điều này, bạn nên bỏ đi rằng bạn được khuyến khích sử dụng đồng đô la trừ khi bạn đặc biệt yêu cầu khả năng tương thích với vỏ Bourne không phải POSIX ban đầu.


26
Bởi hầu hết các ý nghĩa của phản , tôi (và bạn) sẽ nói rằng backticks đang bị phản đối. Đây chủ yếu là một câu hỏi thuật ngữ.
Stéphane Chazelas

4
@StephaneChazelas - Đồng ý! Tôi sẽ tiếp tục nói với ppl rằng họ không được tán thành nhưng backticks chưa chính thức bị "phản đối" theo nghĩa là họ sẽ bị chủ động xóa khỏi cơ sở mã của bất kỳ shell nào trong tương lai gần. Ít nhất là không có gì tôi biết.
slm

3
Giải thích của tôi là backquote được hỗ trợ hoàn toàn vì chúng quá cố thủ trong mã hiện có để chính thức phản đối. Tôi chưa bao giờ nghe một đối số để tiếp tục sử dụng chúng trong mã mới.
chepner

3
@slm Vâng, tôi đoán bạn đã hiểu - Tôi đã bị kéo đi và không để ý. Hầu như không có lý do để sử dụng những thứ này, ngoại trừ việc nó có thể sạch hơn một chút khi xếp lớp các lớp con nên $( cmd `cmd`)chỉ hơi lộn xộn hơn $( cmd $(cmd))- dễ đọc hơn. Tôi luôn luôn coi một tính năng không dùng nữa trong phần mềm là một tính năng chính thức bị loại bỏ bởi thượng nguồn - và tôi chưa bao giờ nghe thấy bất cứ điều gì như thế. Tôi không quan tâm - không có tình yêu với ngôi mộ.
mikeerv

3
Bạn có thể muốn thêm trích dẫn sau từ cơ sở tiêu chuẩn POSIX : Do những hành vi không nhất quán này, sự thay thế lệnh được trích dẫn không được khuyến nghị cho các ứng dụng mới thay thế lệnh lồng hoặc cố gắng nhúng các tập lệnh phức tạp. Mặc dù đây không phải là sự phản đối chính thức vì phần cơ sở là thông tin và không mang tính quy phạm, nhưng điều đó cho thấy nên tiếp tục sử dụng backticks.
jw013

15

Nó không được phản đối, nhưng backticks ( `...`) là cú pháp kế thừa được yêu cầu chỉ bởi những vỏ bourne không tương thích POSIX lâu đời nhất và $(...)là POSIX và được ưa thích hơn vì nhiều lý do:

  • Dấu gạch chéo ngược ( \) bên trong backticks được xử lý theo cách không rõ ràng:

    $ 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 \\
    
  • Báo giá lồng nhau bên trong $()là thuận tiện hơn nhiều:

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

    thay vì:

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

    hoặc viết một cái gì đó như:

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

    bởi vì $()sử dụng một bối cảnh hoàn toàn mới để trích dẫn

    vốn không có khả năng di động vì đạn Bourne và Korn sẽ yêu cầu các dấu gạch chéo ngược này, trong khi Bash và dash thì không.

  • Cú pháp để thay thế lệnh lồng nhau dễ dàng hơn:

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

    hơn:

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

    bởi vì $()thực thi một bối cảnh hoàn toàn mới để trích dẫn, do đó, mỗi thay thế lệnh được bảo vệ và có thể được xử lý riêng mà không cần quan tâm đặc biệt đến trích dẫn và thoát. Khi sử dụng backticks, nó trở nên xấu hơn và xấu hơn sau hai cấp độ trở lên.

    Một vài ví dụ khác:

    echo `echo `ls``      # INCORRECT
    echo `echo \`ls\``    # CORRECT
    echo $(echo $(ls))    # CORRECT
    
  • Nó giải quyết vấn đề về hành vi không nhất quán khi sử dụng backquote:

    • echo '\$x' đầu ra \$x
    • echo `echo '\$x'` đầu ra $x
    • echo $(echo '\$x') đầu ra \$x
  • Cú pháp Backticks có các hạn chế lịch sử đối với nội dung của lệnh nhúng và không thể xử lý một số tập lệnh hợp lệ bao gồm backquote, trong khi $()biểu mẫu mới hơn có thể xử lý bất kỳ loại tập lệnh nhúng hợp lệ nào.

    Ví dụ: các tập lệnh nhúng hợp lệ này không hoạt động ở cột bên trái, nhưng hoạt động ở bên phải 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 ')'
    `                              )
    

Do đó, cú pháp thay thế lệnh$ -prefixed nên là phương thức ưa thích, vì nó rõ ràng với cú pháp rõ ràng (cải thiện khả năng đọc của người và máy), nó có thể lồng vào nhau và trực quan, phân tích cú pháp bên trong của nó là riêng biệt và cũng phù hợp hơn (với tất cả các bản mở rộng khác được phân tích cú pháp từ trong dấu ngoặc kép) trong đó backticks là ngoại lệ duy nhất và ký tự dễ dàng được ngụy trang khi liền kề để làm cho nó khó đọc hơn, đặc biệt là với các phông chữ nhỏ hoặc bất thường.`"

Nguồn: Tại sao được $(...)ưa thích hơn `...`(backticks)? tại BashFAQ

Xem thêm:

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.