Câu trả lời:
`date` sẽ chỉ mở rộng ra đầu ra của date
lệ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 echo
lệ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 echo
lệ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 .
date
lệnh trần .
Cả hai
echo `date`
và
echo "`date`"
sẽ hiển thị ngày. Đầu ra từ cái sau trông giống như đầu ra từ date
chí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 echo
dướ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ì echo
chỉ 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 foo
muố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
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 date
vớ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ư echo
trong trường hợp của bạn), việc mở rộng đó phải chịu thêm:
Chia tách từ : đó là "đầu ra của date
các ký tự dòng mới bị tước" được phân tách theo giá trị hiện tại của $IFS
biế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 date
kế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à $IFS
hiện có :
, thì sẽ được chia thành 3 từ : Fri 1 Nov 14
, 11
và 15 GMT 2013
.
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
là ?%? 33 */*/* UVC 3432
(như nó thường là ở những nơi sao Kim và UVC múi giờ), và $IFS
là 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 UVC
và 3432
.Đó là lý do tại sao:
$IFS
thành các ký tự bạn muốn tách.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 -x
giú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, zsh
giữ 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
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`