Cách chính xác để gọi một số lệnh được lưu trữ trong biến là gì?
Có sự khác biệt nào giữa 1 và 2 không?
#!/bin/sh
cmd="ls -la $APPROOTDIR | grep exception"
#1
$cmd
#2
eval "$cmd"
Cách chính xác để gọi một số lệnh được lưu trữ trong biến là gì?
Có sự khác biệt nào giữa 1 và 2 không?
#!/bin/sh
cmd="ls -la $APPROOTDIR | grep exception"
#1
$cmd
#2
eval "$cmd"
Câu trả lời:
Các trình bao Unix vận hành một loạt các phép biến đổi trên mỗi dòng đầu vào trước khi thực thi chúng. Đối với hầu hết các shell, nó trông giống như thế này (lấy từ bash
manpage):
Việc sử dụng $cmd
trực tiếp sẽ được thay thế bằng lệnh của bạn trong giai đoạn mở rộng tham số và sau đó nó trải qua tất cả các phép biến đổi sau.
Việc sử dụng eval "$cmd"
không có tác dụng gì cho đến khi giai đoạn loại bỏ dấu ngoặc kép, nơi $cmd
được trả về như cũ và được chuyển dưới dạng tham số tới eval
, có chức năng là chạy lại toàn bộ chuỗi trước khi thực thi.
Vì vậy, về cơ bản, chúng giống nhau trong hầu hết các trường hợp và khác nhau khi lệnh của bạn sử dụng các bước chuyển đổi để mở rộng tham số. Ví dụ: sử dụng mở rộng dấu ngoặc nhọn:
$ cmd="echo foo{bar,baz}"
$ $cmd
foo{bar,baz}
$ eval "$cmd"
foobar foobaz
eval "$cmd"
mà không cần viết eval
? $($cmd)
? ${$cmd}
?
eval
phép toán phân tích cú pháp dữ liệu; do đó nó rất nhạy cảm về bảo mật và làm điều đó một cách ngầm định sẽ là một hình thức rất tệ.
Nếu bạn chỉ làm eval $cmd
khi chúng tôi làm cmd="ls -l"
(tương tác và trong một tập lệnh) thì chúng tôi sẽ có được kết quả mong muốn. Trong trường hợp của bạn, bạn có một đường ống có grep không có mẫu, vì vậy phần grep sẽ không thành công với một thông báo lỗi. Just $cmd
sẽ tạo ra một thông báo "lệnh không tìm thấy" (hoặc một số như vậy). Vì vậy, hãy thử sử dụng eval và sử dụng một lệnh đã hoàn thành, không phải lệnh tạo ra thông báo lỗi.
$cmd
sẽ chỉ thay thế biến bằng giá trị của nó để được thực thi trên dòng lệnh.
eval "$cmd"
mở rộng biến & thay thế lệnh trước khi thực thi giá trị kết quả trên dòng lệnh
Phương pháp thứ hai hữu ích khi bạn muốn chạy các lệnh không linh hoạt, ví dụ:
for i in {$a..$b}
vòng lặp định dạng sẽ không hoạt động vì nó không cho phép các biến.
Trong trường hợp này, một đường ống để bash hoặc eval là một cách giải quyết.
Đã thử nghiệm trên Mac OSX 10.6.8, Bash 3.2.48
Tôi nghĩ bạn nên đặt
`
(biểu tượng backtick) xung quanh biến của bạn.