Sự khác biệt giữa $ (lệnh) và `lệnh` trong lập trình shell là gì?


258

Để lưu trữ đầu ra của một lệnh dưới dạng một biến trong sh / ksh / bash, bạn có thể thực hiện một trong hai

var=$(command)

hoặc là

var=`command`

Sự khác biệt nếu có giữa hai phương pháp là gì?



Bạn sẽ tìm thấy vấn đề lồng nhau chi tiết trong Hướng dẫn mã hóa Git: xem câu trả lời của tôi dưới đây .
VonC

Câu trả lời:


274

Backticks / gravemarks đã không được dùng $()để thay thế lệnh vì $()có thể dễ dàng lồng vào nhau như trong $(echo foo$(echo bar)). Có những khác biệt khác như cách dấu gạch chéo ngược được phân tích cú pháp trong phiên bản backtick / gravemark, v.v.

Xem BashFAQ / 082 để biết một số lý do để luôn thích cú pháp $ (...).

Cũng xem thông số POSIX để biết thông tin chi tiết về sự khác biệt khác nhau.


25
Liên kết tốt, nhưng văn bản đó không phản đối các phản hồi có lợi cho $(...)- nó chỉ lưu ý chúng là các lựa chọn thay thế.
Norman Gray

24
@NormanGray POSIX có thể không nói từ đó bị phản đối nhưng nó nói "the backquoted variety of command substitution is not recommended"đó chỉ là một cách nói dài dòng bị phản đối IMHO
SiegeX

11
POSIX đã không phản đối backticks, mà được thêm vào $(...)như một phương pháp thay thế. Không có lỗi thực hiện đã biết với backticks, nhưng có nhiều lỗi thực hiện đã biết với $(...) . Vì vậy, đối với các vấn đề về tính di động, nên sử dụng backticks cho các cuộc gọi không lồng nhau. $(...)cần một trình phân tích cú pháp đệ quy nhưng điều này không được sử dụng với ksh86 đã giới thiệu tính năng này. Kiểm tra in-ulm.de/~mascheck/various/cmd-subst để biết danh sách các triển khai chính xác. Một vỏ phù hợp cần hỗ trợ tất cả các trường hợp ngoại trừ trường hợp D.2.
schily

2
Có những thứ khác trong POSIX cần được xem là deprecated, ví dụ như việc sử dụng waitpid()ngăn bạn nhìn thấy toàn bộ 32 bit từ exit()tham số, nhưng tất cả các shell ngoại trừ Bourne Shell gần đây vẫn sử dụng waitpid()thay vì waitid()cuộc gọi hiện có 26 năm.
schily

Liên kết trong câu trả lời gợi ý rằng có một số khác biệt giữa các backticks và $(), được giải thích nhiều hơn trong phần này của tài liệu . Sự khác biệt không chỉ là về làm tổ.
Một số lập trình viên anh chàng

39

Họ cư xử giống nhau. Sự khác biệt là cú pháp: nó dễ làm tổ $()hơn ``:

listing=$(ls -l $(cat filenames.txt))

so với

listing=`ls -l \`cat filenames.txt\``

10
echo $(echo \$abc)không giống như echo `echo \$abc`‍- Sự khác biệt cũng tồn tại cho $(echo \`)$(echo \\)
Peter.O

Khác biệt nữa là: echo foo `#comment`vs echo foo $(#comment). Cái thứ hai không hoạt động. (Được sử dụng để bình luận trong một lệnh nhiều dòng.)
wvducky

27

Tháng 7 năm 2014: Cam kết f25f5e6 (của Elia Pinto ( devzero2000) , tháng 4 năm 2014, Git 2.0) thêm vào vấn đề lồng nhau:

Biểu mẫu được trích dẫn là phương thức truyền thống để thay thế lệnh và được POSIX hỗ trợ.
Tuy nhiên, tất cả nhưng việc sử dụng đơn giản nhất trở nên phức tạp một cách nhanh chóng.
Cụ thể, thay thế lệnh nhúng và / hoặc sử dụng dấu ngoặc kép yêu cầu thoát cẩn thận với ký tự dấu gạch chéo ngược
.

Đó là lý do tại sao git / Documentation / CodingGuiances đề cập:

Chúng tôi muốn $( ... )thay thế lệnh; Không giống như ``, nó đúng cách làm tổ .
Đáng lẽ ra nó phải là cách Bourne đánh vần từ ngày đầu, nhưng thật không may.

Thiton bình luận :

Đó là lý do tại sao `echo `foo`` nói chung sẽ không hoạt động vì sự mơ hồ vốn có bởi vì mỗi cái ``có thể được mở hoặc đóng.
Nó có thể hoạt động cho các trường hợp đặc biệt do may mắn hoặc các tính năng đặc biệt.


Cập nhật tháng 1 năm 2016: Git 2.8 (tháng 3 năm 2016) được loại bỏ hoàn toàn backticks.

Xem cam kết ec1b763 , cam kết 9c10377 , cam kết c7b793a , cam kết 80a6b3f , cam kết 9375dcf , cam kết e74ef60 , cam kết 27fe43e , cam kết 2525c51 , cam kết becd67f , cam kết a5c98ac , cam kết 8c311f9 , cam kết 57da049 , cam kết 1d9e86f , cam kết 78ba28d , cam kết efa639f , cam kết 1be2fa0 , cam kết 38e9476 , cam kết 8823d2f , cam kết 32858a0 , cam kết cd914d8(12 tháng 1 năm 2016) bởi Elia Pinto ( devzero2000) .
(Được hợp nhất bởi Junio ​​C Hamano - gitster- trong cam kết e572fef , ngày 22 tháng 1 năm 2016)

Từ Git 2.8 trở đi, tất cả $(...), không còn nữa `...`.


2
$()cũng được chỉ định POSIX - một trích dẫn mô tả backticks là "hỗ trợ POSIX" theo cách ám chỉ rằng điều này là duy nhất đối với họ là sai lệch. Đó là giai đoạn tiền POSIX duy nhất (thời 1970), trong đó backticks là cú pháp được hỗ trợ duy nhất.
Charles Duffy

25

Khi biểu mẫu back-tick cũ được sử dụng, dấu gạch chéo ngược vẫn giữ nguyên nghĩa đen của nó trừ khi được theo sau bởi $, `hoặc \. Dấu kiểm ngược đầu tiên không có trước dấu gạch chéo ngược chấm dứt thay thế lệnh.

Khi sử dụng $(command)mẫu mới hơn , tất cả các ký tự giữa các dấu ngoặc đơn tạo thành lệnh; không ai được điều trị đặc biệt

Cả hai hình thức có thể được lồng nhau, nhưng giống back-tick yêu cầu hình thức sau.

`echo \`foo\`` 

Như trái ngược với:

$(echo $(foo))

1
Chỉnh sửa nhỏ, cả phiên bản backtick và $()phiên bản đều tuân thủ POSIX.
Cuộc bao vây

5

Có rất ít sự khác biệt, ngoại trừ những ký tự không được giải mã mà bạn có thể sử dụng bên trong lệnh. Bạn thậm chí có thể đặt các lệnh `...` bên trong các lệnh $ (...) (và ngược lại) để thay thế lệnh hai cấp độ sâu phức tạp hơn.

Có một cách giải thích khác nhau về ký tự / toán tử dấu gạch chéo ngược. Trong số những thứ khác, khi lồng các lệnh thay thế `...` , bạn phải thoát các ký tự ` bên trong bằng \, trong khi với trạm biến áp $ (), nó hiểu tự động lồng nhau.


0

"Sự khác biệt nếu có giữa hai phương pháp là gì?"

Hãy chú ý đến hành vi này:

A="A_VARIABLE"
echo "$(echo "\$A")"
echo "`echo "\$A"`"

Bạn sẽ nhận được những kết quả này:

$A
A_VARIABLE

 

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.