Sự lựa chọn là của bạn. Nếu bạn không trích dẫn $@
bất kỳ giá trị nào của nó trải qua mở rộng và giải thích bổ sung. Nếu bạn trích dẫn nó, tất cả các đối số được thông qua, hàm sẽ được sao chép trong nguyên văn mở rộng của nó. Bạn sẽ không bao giờ có thể xử lý một cách đáng tin cậy các mã thông báo cú pháp shell như thế nào &>|
, v.v.
- Chính xác các từ được sử dụng trong việc thực hiện một lệnh đơn giản với
"$@"
.
...hoặc là...
- Một phiên bản mở rộng và diễn giải thêm các đối số của bạn mà sau đó chỉ được áp dụng cùng nhau như một lệnh đơn giản với
$@
.
Không có cách nào là sai nếu nó là cố ý và nếu tác động của những gì bạn chọn được hiểu rõ. Cả hai cách đều có lợi thế so với cách khác, mặc dù lợi thế của cách thứ hai hiếm khi đặc biệt hữu ích. Vẫn...
(run_this(){ $@; }; IFS=@ run_this 'ls@-dl@/tmp')
drwxrwxrwt 22 root root 660 Dec 28 19:58 /tmp
... nó không vô dụng , hiếm khi có khả năng được sử dụng nhiều . Và trong một bash
vỏ, vì bash
mặc định không gắn một định nghĩa biến với môi trường của nó ngay cả khi định nghĩa đã nói được đặt trước dòng lệnh của một nội dung đặc biệt hoặc cho một hàm, giá trị toàn cục $IFS
không bị ảnh hưởng và khai báo của nó là cục bộ Chỉ để run_this()
gọi.
Tương tự:
(run_this(){ $@; }; set -f; run_this ls -l \*)
ls: cannot access *: No such file or directory
... Globing cũng có thể cấu hình. Trích dẫn phục vụ một mục đích - chúng không phải là không có gì. Không có chúng mở rộng vỏ trải qua giải thích thêm - giải thích cấu hình . Nó đã từng - với một số vỏ rất cũ - $IFS
được áp dụng trên toàn cầu cho tất cả các đầu vào, và không chỉ mở rộng. Trong thực tế, các shell cho biết hành vi rất giống như run_this()
ở chỗ chúng đã phá vỡ tất cả các từ đầu vào trên giá trị của $IFS
. Và vì vậy, nếu những gì bạn đang tìm kiếm là hành vi vỏ rất cũ, thì bạn nên sử dụng run_this()
.
Tôi không tìm kiếm nó, và tôi khá khó khăn vào lúc này để đưa ra một ví dụ hữu ích cho nó. Tôi thường thích các lệnh mà shell của tôi chạy là các lệnh mà tôi gõ vào nó. Và vì vậy, được lựa chọn, tôi sẽ luôn luôn như vậy run_that()
. Ngoại trừ việc...
(run_that(){ "$@"; }; IFS=l run_that 'ls' '-ld' '/tmp')
drwxrwxrwt 22 root root 660 Dec 28 19:58 /tmp
Chỉ cần bất cứ điều gì có thể được trích dẫn. Các lệnh sẽ chạy trích dẫn. Nó hoạt động vì vào thời điểm lệnh thực sự chạy, tất cả các từ đầu vào đã trải qua quá trình loại bỏ trích dẫn - đó là giai đoạn cuối cùng của quá trình giải thích đầu vào của shell. Vì vậy, sự khác biệt giữa 'ls'
và ls
chỉ có thể quan trọng trong khi shell đang diễn giải - và đó là lý do tại sao trích dẫn ls
đảm bảo rằng bất kỳ bí danh nào được đặt tên ls
không được thay thế cho ls
từ lệnh được trích dẫn của tôi . Ngoài ra, điều duy nhất mà trích dẫn ảnh hưởng là phân định các từ (đó là cách thức và lý do trích dẫn biến / đầu vào khoảng trắng) và cách giải thích các ký tự đại diện và các từ dành riêng.
Vì thế:
'for' f in ...
do :
done
bash: for: command not found
bash: do: unexpected token 'do'
bash: do: unexpected token 'done'
Bạn sẽ không bao giờ có thể làm điều đó với một trong hai run_this()
hoặc run_that()
.
Nhưng tên hàm, hoặc $PATH
các lệnh hoặc lệnh dựng sẽ thực thi tốt chỉ trích dẫn hoặc không trích dẫn, và đó chính xác là cách thức run_this()
và run_that()
hoạt động ở vị trí đầu tiên. Bạn sẽ không thể làm bất cứ điều gì hữu ích với $<>|&(){}
bất kỳ ai trong số đó. Ngắn gọn eval
, là.
(run_that(){ "$@"; }; run_that eval printf '"%s\n"' '"$@"')
eval
printf
"%s\n"
"$@"
Nhưng không có nó, bạn bị giới hạn bởi các giới hạn của một lệnh đơn giản nhờ vào các trích dẫn bạn sử dụng (ngay cả khi bạn không$@
sử dụng vì các hành động như một trích dẫn ở đầu quá trình khi lệnh được phân tích cú pháp cho các siêu ký tự) . Ràng buộc tương tự cũng đúng với các bài tập và chuyển hướng dòng lệnh, được giới hạn trong dòng lệnh của hàm. Nhưng đó không phải là một vấn đề lớn:
(run_that(){ "$@";}; echo hey | run_that cat)
hey
Tôi có thể dễ dàng <
chuyển hướng đầu vào hoặc >
đầu ra ở đó như tôi đã mở đường ống.
Dù sao, trong một cách xoay vòng, không có cách nào đúng hay sai ở đây - mỗi cách đều có cách sử dụng. Chỉ là bạn nên viết nó khi bạn định sử dụng nó, và bạn nên biết bạn muốn làm gì. Bỏ dấu ngoặc kép có thể có một mục đích - nếu không thì sẽ không có trích dẫn nào cả - nhưng nếu bạn bỏ qua chúng vì những lý do không liên quan đến mục đích của bạn, bạn chỉ đang viết mã xấu. Làm những gì bạn có ý nghĩa; Tôi cố gắng nào.
run_that
Hành vi của nó chắc chắn là những gì tôi mong đợi (nếu có một khoảng trống trong đường dẫn đến lệnh thì sao?). Nếu bạn muốn có hành vi khác, chắc chắn bạn sẽ bỏ qua nó tại trang web cuộc gọi nơi bạn biết dữ liệu là gì? Tôi hy vọng sẽ gọi chức năng này làrun_that ls -l
, hoạt động tương tự trong cả hai phiên bản. Có một trường hợp khiến bạn mong đợi khác nhau?