Sự khác biệt giữa echo `date`, echo Hồi` date`, và echo '` date`' là gì?


22

Sự khác biệt giữa ba lệnh này là gì?

echo `date`
echo "`date`"
echo '`date`'

Tôi bối rối về sự khác biệt thực sự là gì. Tôi nghĩ rằng khi 'xung quanh nó có nghĩa là nó là một chuỗi, do đó echo sẽ xuất ra chuỗi theo nghĩa đen datethay vì hiển thị ngày?

Câu trả lời:


19

`date` sẽ chỉ mở rộng ra đầu ra của datelệnh. Tuy nhiên, nó loại bỏ các ký tự khoảng trắng thừa ở những nơi có nhiều hơn một ký tự khoảng trắng liên tiếp trong đầu ra. (Điều này là do sự thay thế lệnh chịu sự phân tách từ và vì cách echolệnh xử lý nhiều đối số.)

Trong "` date` " , dấu ngoặc kép là dấu ngoặc kép yếu, vì vậy chúng sẽ mở rộng các biến (thử" $ PWD ") và thực hiện thay thế lệnh. Kết quả của việc mở rộng được truyền dưới dạng một đối số duy nhất cho echolệnh, với bất kỳ khoảng trắng liên tiếp nào được bao gồm: đó là việc tách từ không được thực hiện.

Trong '`date`' , các trích dẫn đơn là các trích dẫn mạnh hơn, vì vậy chúng sẽ không cho phép mở rộng các biến hoặc thay thế lệnh trong chúng.

Tham khảo liên kết này để giải thích thêm.

Chỉnh sửa điểm đầu tiên như được chỉ định chính xác bởi Michael Suelmann trong bình luận dưới đây .


1
Chính xác thì ký tự `xung quanh ngày được gọi là gì? Nếu tôi hiểu chính xác, các ký tự meta sẽ không hoạt động trong các trích dẫn đơn?
Giăng

Nếu tôi hiểu chính xác, các ký tự meta sẽ không hoạt động trong các trích dẫn đơn?
Giăng

8
`Thường được gọi là" backtick "trong kịch bản đó và các tài liệu / sách Unix khác nhau. Nó không thực sự được sử dụng như một trọng âm Unicode khi nó tự nó như thế, mặc dù đó là tên của biểu tượng. Và bạn đã đúng rằng sẽ không có sự mở rộng của các siêu ký tự / biểu thức nếu bạn bao quanh nó bằng các dấu ngoặc đơn.
Jim Stewart

Tuyên bố đầu tiên của bạn không chính xác vì đầu ra có thể hơi khác nhau tùy thuộc vào ngày hoặc ngôn ngữ. Chỉ có lệnh thứ hai sẽ xuất ra điều tương tự như datelệnh trần .
jlliagre

1
@BonsiScott Không gian thêm giữa "tháng 11" và "1" cũng bị xóa trong HTML;)
Izkata

16

Cả hai

echo `date`

echo "`date`"

sẽ hiển thị ngày. Đầu ra từ cái sau trông giống như đầu ra từ datechính nó.

Tuy nhiên, có một sự khác biệt: một trong những "trích dẫn "được bao quanh sẽ được gửi đến echodưới dạng một đối số duy nhất. Các trích dẫn đóng gói đầu ra của toàn bộ lệnh dưới dạng một đối số. Vì echochỉ cần in ra các đối số của nó theo thứ tự, với khoảng trắng ở giữa, về cơ bản nó sẽ trông giống nhau.

Đây là một ví dụ về sự khác biệt tinh tế:

echo `date`

sản xuất:

Fri Nov 1 01:48:45 EST 2013

nhưng:

echo "`date`"

sản xuất:

Fri Nov  1 01:48:49 EST 2013

Lưu ý rằng hai khoảng trắng sau Novđược giảm xuống một mà không có dấu ngoặc kép. Điều này là do shell đang phân tích cú pháp từng phần tử được phân tách bằng dấu cách và gửi kết quả tới echo dưới dạng 6 đối số. Khi bạn trích dẫn nó, echo nhận được một đối số duy nhất và dấu ngoặc kép giữ khoảng trống.

Điều này trở nên quan trọng hơn nhiều trong các lệnh khác ngoài echo. Ví dụ, hãy tưởng tượng một lệnh foomuốn có hai đối số: ngày và địa chỉ email.

Điều này sẽ làm việc trong kịch bản đó:

foo "`date`" joeuser@example.com

Nhưng điều này sẽ gây nhầm lẫn cho tập lệnh bằng cách gửi cho nó 7 đối số:

foo `date` joeuser@example.com

3
Bạn đang mâu thuẫn trong câu đầu tiên của bạn. Biểu mẫu thứ nhất và thứ hai sẽ không luôn xuất ra điều tương tự như bạn chứng minh sau này.
jlliagre

Cảm ơn. Tôi đã thay đổi từ ngữ để làm cho nó rõ ràng hơn.
Jim Stewart

3

Trong shell POSIX, `date`là hình thức thay thế lệnh cổ xưa. Cú pháp hiện đại là $(date).

Trong cả hai trường hợp, chúng mở rộng thành đầu ra datevới các ký tự dòng mới bị loại bỏ (với điều kiện đầu ra không chứa các ký tự NUL).

Tuy nhiên, khi không nằm trong dấu ngoặc kép và trong bối cảnh danh sách (ví dụ: trong các đối số cho các lệnh đơn giản như echotrong trường hợp của bạn), việc mở rộng đó phải chịu thêm:

  1. Chia tách từ : đó là "đầu ra của datecác ký tự dòng mới bị tước" được phân tách theo giá trị hiện tại của $IFSbiến (theo mặc định có chứa khoảng trắng, tab và dòng mới (và NUL với zsh)) thành nhiều từ .

    Chẳng hạn, nếu các datekết quả đầu ra Fri 1 Nov 14:11:15 GMT 2013\n(giống như thường xuất hiện ở một miền địa phương tiếng Anh và theo múi giờ của lục địa Anh) và $IFShiện có :, thì sẽ được chia thành 3 từ : Fri 1 Nov 14, 1115 GMT 2013.

  2. Thế hệ tên tập tin (aka globbing ) (trừ trường hợp zsh): có nghĩa là, mỗi từ phát sinh từ việc tách trên được xem xét cho ký tự đại diện ( *, ?, [...]mặc dù một số vỏ có nhiều), và mở rộng vào danh sách các tên tập tin phù hợp với những mô hình. Ví dụ, nếu đầu ra của date?%? 33 */*/* UVC 3432(như nó thường là ở những nơi sao Kim và UVC múi giờ), và $IFSlà giá trị mặc định), sau đó mở rộng để tất cả các phi ẩn 3 tên tập tin nhân vật trong thư mục hiện có nhân vật trung là %, 33, tất cả các tệp không bị ẩn trong tất cả các thư mục con không bị ẩn của tất cả các thư mục con không bị ẩn của thư mục hiện tại UVC3432.

Đó là lý do tại sao:

  1. Bạn phải luôn luôn trích dẫn (với dấu ngoặc kép) thay thế lệnh trừ khi bạn muốn tách từ hoặc tạo tên tệp được thực hiện khi mở rộng.
  2. Nếu bạn muốn tách từ , thì bạn nên đặt $IFSthành các ký tự bạn muốn tách.
  3. Nếu bạn muốn tách từ nhưng không tạo tên tệp , bạn cần phát hành một set +fđể vô hiệu hóa nó.

Các trích dẫn duy nhất trích dẫn tất cả mọi thứ vì vậy làm cho các ký tự backtick được thực hiện theo nghĩa đen.

Ví dụ (sử dụng -xgiúp dễ dàng nhìn thấy những gì đang diễn ra):

$ bash --norc -x
bash-4.2$ IFS=:
+ IFS=:
bash-4.2$ echo `date`
++ date
+ echo 'Fri  1 Nov 14' 42 '33 GMT 2013'
Fri  1 Nov 14 42 33 GMT 2013
bash-4.2$ echo "`date`"
++ date
+ echo 'Fri  1 Nov 14:42:41 GMT 2013'
Fri  1 Nov 14:42:41 GMT 2013

bash-4.2$ cd /lib/modules
+ cd /lib/modules
bash-4.2$ export TZ=UVC LC_ALL=vs_VS
+ export TZ=UVC LC_ALL=vs_VS
+ TZ=UVC
+ LC_ALL=vs_VS
bash-4.2$ unset -v IFS     # get the default behaviour
+ unset -v IFS
bash-4.2$ echo `date`
++ date
+ echo '?%?' 33 3.10-2-amd64/build/arch 3.10-2-amd64/build/include 3.10-2-amd64/build/Makefile 3.10-2-amd64/build/Module.symvers 3.10-2-amd64/build/scripts 3.10-2-amd64/kernel/arch 3.10-2-amd64/kernel/crypto 3.10-2-amd64/kernel/drivers 3.10-2-amd64/kernel/fs 3.10-2-amd64/kernel/lib 3.10-2-amd64/kernel/mm 3.10-2-amd64/kernel/net 3.10-2-amd64/kernel/sound 3.10-2-amd64/source/arch 3.10-2-amd64/source/include 3.10-2-amd64/source/Makefile 3.10-2-amd64/source/scripts 3.10-2-amd64/updates/dkms 3.10-3-amd64/build/arch 3.10-3-amd64/build/include 3.10-3-amd64/build/Makefile 3.10-3-amd64/build/Module.symvers 3.10-3-amd64/build/scripts 3.10-3-amd64/kernel/arch 3.10-3-amd64/kernel/crypto 3.10-3-amd64/kernel/drivers 3.10-3-amd64/kernel/fs 3.10-3-amd64/kernel/lib 3.10-3-amd64/kernel/mm 3.10-3-amd64/kernel/net 3.10-3-amd64/kernel/sound 3.10-3-amd64/source/arch 3.10-3-amd64/source/include 3.10-3-amd64/source/Makefile 3.10-3-amd64/source/scripts 3.10-3-amd64/updates/dkms UVC 3432
?%? 33 3.10-2-amd64/build/arch 3.10-2-amd64/build/include 3.10-2-amd64/build/Makefile 3.10-2-amd64/build/Module.symvers 3.10-2-amd64/build/scripts 3.10-2-amd64/kernel/arch 3.10-2-amd64/kernel/crypto 3.10-2-amd64/kernel/drivers 3.10-2-amd64/kernel/fs 3.10-2-amd64/kernel/lib 3.10-2-amd64/kernel/mm 3.10-2-amd64/kernel/net 3.10-2-amd64/kernel/sound 3.10-2-amd64/source/arch 3.10-2-amd64/source/include 3.10-2-amd64/source/Makefile 3.10-2-amd64/source/scripts 3.10-2-amd64/updates/dkms 3.10-3-amd64/build/arch 3.10-3-amd64/build/include 3.10-3-amd64/build/Makefile 3.10-3-amd64/build/Module.symvers 3.10-3-amd64/build/scripts 3.10-3-amd64/kernel/arch 3.10-3-amd64/kernel/crypto 3.10-3-amd64/kernel/drivers 3.10-3-amd64/kernel/fs 3.10-3-amd64/kernel/lib 3.10-3-amd64/kernel/mm 3.10-3-amd64/kernel/net 3.10-3-amd64/kernel/sound 3.10-3-amd64/source/arch 3.10-3-amd64/source/include 3.10-3-amd64/source/Makefile 3.10-3-amd64/source/scripts 3.10-3-amd64/updates/dkms UVC 3432
bash-4.2$ echo "`date`"
++ date
+ echo '?%? 33 */*/* UVC 3432'
?%? 33 */*/* UVC 3432

Nếu đầu ra chứa các ký tự NUL, thì hành vi thay đổi từ shell sang shell: một số loại bỏ chúng, một số cắt bớt đầu ra ở ký tự NUL đầu tiên, zshgiữ nguyên chúng nhưng lưu ý rằng dù sao các lệnh bên ngoài không thể lấy các đối số có chứa NUL


Không có thứ gọi là "vỏ POSIX" thực sự. Có các shell có thể tuân thủ các tiêu chuẩn POSIX khác nhau bằng cách sử dụng một tập hợp con giới hạn của chức năng của chúng.
fpmurphy

0

Với `date`, bạn nhận được đầu ra của ngày được chia thành nhiều từ, vì việc chia từ được thực hiện sau khi thay thế lệnh.

Với "` date` ", bạn nhận được đầu ra của ngày dưới dạng một từ / tham số vì có sự thay thế lệnh giữa các dấu ngoặc kép, nhưng đầu ra không được phân tích cú pháp thêm. Điều tương tự cũng hợp lệ với mở rộng biến như "$ i" trong ví dụ của tôi dưới đây.

Với '`date`', bạn có được một 'ngày' theo nghĩa đen vì không có lệnh thay thế giữa các dấu ngoặc đơn.

Có lẽ sự khác biệt của 3 hình thức sẽ được thể hiện rõ hơn theo cách này:

> for i in `date`; do echo "$i"; done
Fr
1.
Nov
12:25:30
CET
2013

> for i in "`date`"; do echo "$i"; done
Fr 1. Nov 12:25:38 CET 2013

> for i in '`date`'; do echo "$i"; done
`date`
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.