Làm thế nào để thực thi lệnh được lưu trữ trong một biến?


Câu trả lời:


95

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ừ bashmanpage):

  • tách từ ban đầu
  • mở rộng nẹp
  • mở rộng dấu ngã
  • khai triển tham số, biến và số học
  • thay thế lệnh
  • tách từ thứ cấp
  • mở rộng đường dẫn (hay còn gọi là globbing)
  • trích dẫn loại bỏ

Việc sử dụng $cmdtrự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

6
Làm thế nào để làm gì eval "$cmd"mà không cần viết eval? $($cmd)? ${$cmd}?
Steven Lu

2
@StevenLu, không cái nào trong số đó là tương đương - cố ý như vậy: Một evalphé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ệ.
Charles Duffy

5

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 $cmdsẽ 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.


Nó chỉ là sai lầm. Nên là "ngoại lệ grep".
Volodymyr Bezuglyy

sau đó sử dụng eval, không phải $ cmd, vì nó có thể sẽ không hoạt động (nó không hoạt động trong thử nghiệm của tôi, dưới bash và zsh). Đây là những gì eval đã có nghĩa là để làm ...
Henno Brandsma

0

$cmdsẽ 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


-4

Tôi nghĩ bạn nên đặt

`

(biểu tượng backtick) xung quanh biến của bạn.


4
Điều này thực hiện đầu ra của lệnh, ví dụ như trong trường hợp ls -l sẽ tạo ra một thông báo như lệnh "tổng" không tìm thấy "(bởi vì tổng ... là một phần của đầu ra của ls -l, ví dụ) Vì vậy, đây là KHÔNG những gì bạn muốn.
Henno Brandsma
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.