Thêm đối số vào 'bash -c'


22

Hãy nói rằng tôi muốn chạy một lệnh thông qua Bash như thế này:

/bin/bash -c "ls -l"

Theo trang người đàn ông Bash, tôi cũng có thể chạy nó như thế này:

#               don't process arguments after this one
#               |   pass all unprocessed arguments to command
#               |   |
#               V   V
/bin/bash -c ls -- -l

ngoại trừ nó dường như không hoạt động (dường như bỏ qua). Tôi đang làm gì đó sai, hay tôi đang giải thích trang người đàn ông sai?

Trích dẫn có liên quan từ người đàn ông:

Nếu tùy chọn -c có mặt, thì các lệnh được đọc từ chuỗi. Nếu có các đối số sau chuỗi, chúng được gán cho các tham số vị trí, bắt đầu bằng $ 0.

A - báo hiệu kết thúc các tùy chọn và vô hiệu hóa xử lý tùy chọn tiếp theo. Bất kỳ đối số nào sau - được coi là tên tệp và đối số.

Câu trả lời:


33

Bạn đang hiểu sai trang người đàn ông. Thứ nhất, phần --báo hiệu kết thúc các tùy chọn không liên quan đến những gì bạn đang cố gắng thực hiện. Việc -cghi đè phần còn lại của dòng lệnh kể từ thời điểm đó, do đó nó không còn phải xử lý tùy chọn của bash nữa, nghĩa là nó --sẽ được chuyển qua lệnh, không được xử lý bởi bash như là dấu kết thúc của tùy chọn.

Sai lầm thứ hai là các đối số bổ sung được gán làm tham số vị trí cho quy trình shell được khởi chạy, không được truyền dưới dạng đối số cho lệnh. Vì vậy, những gì bạn đang cố gắng có thể được thực hiện như một trong:

/bin/bash -c 'echo "$0" "$1"' foo bar
/bin/bash -c 'echo "$@"' bash foo bar

Trong trường hợp đầu tiên, truyền echo các tham số $0$1rõ ràng, và trong trường hợp thứ hai, sử dụng "$@"để mở rộng bình thường như "tất cả các tham số vị trí ngoại trừ $ 0". Lưu ý rằng trong trường hợp đó, chúng ta cũng phải vượt qua một cái gì đó để được sử dụng $0; Tôi đã chọn "bash" vì đó là điều $0bình thường, nhưng mọi thứ khác sẽ hoạt động.

Vì lý do nó được thực hiện theo cách này, thay vì chỉ truyền bất kỳ đối số nào bạn đưa trực tiếp vào lệnh bạn liệt kê: lưu ý rằng tài liệu nói "lệnh s được đọc từ chuỗi", số nhiều. Nói cách khác, sơ đồ này cho phép bạn thực hiện:

/bin/bash -c 'mkdir "$1"; cd "$1"; touch "$2"' bash dir file

Nhưng, lưu ý rằng cách tốt hơn để đáp ứng mục tiêu ban đầu của bạn có thể là sử dụng envthay vì bash:

/usr/bin/env -- "ls" "-l"

Nếu bạn không cần bất kỳ tính năng nào mà shell đang cung cấp, không có lý do gì để sử dụng nó - sử dụng envtrong trường hợp này sẽ nhanh hơn, đơn giản hơn và ít gõ hơn. Và bạn không cần phải suy nghĩ nhiều để đảm bảo rằng nó sẽ xử lý một cách an toàn tên tệp có chứa siêu ký tự vỏ hoặc khoảng trắng.


3

Tôi không chắc mục tiêu của bạn là gì, nhưng nếu bạn chỉ đơn giản là cố gắng xây dựng một cỗ máy Rube Goldberg - thì một thiết bị, phát minh, thiết bị hoặc thiết bị được cố tình chế tạo quá mức hoặc quá mức để thực hiện một nhiệm vụ rất đơn giản trong một nhiệm vụ rất đơn giản thời trang phức tạp - sau đó thử

sh -c 'ls $0' -l

hoặc là

sh -c 'ls $1' supercalifragilisticexpialidocious -l

hoặc thậm chí

sh -c 'ls -$0' l

Bạn sẽ có thể hiểu làm thế nào những điều này làm việc từ câu trả lời của godlygeek.

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.