Echo một lệnh đuôi tạo ra đầu ra bất ngờ?


8

Lệnh này, khi chạy một mình, tạo ra kết quả mong đợi (dòng cuối cùng của crontab):

tail -n 1 /etc/crontab

Tuy nhiên, khi tôi chạy nó như một phần của lệnh echo để gửi kết quả đến một tệp, nó sẽ thêm một bản tóm tắt của tất cả các tệp trong thư mục làm việc, cộng với kết quả mong đợi:

sudo bash -c 'echo $(tail -n 1 /etc/crontab) > /path/to/file'

Tại sao lệnh này tạo ra dữ liệu bổ sung?



3
Bạn đang echolàm gì ở đây vậy? Cũng xem xéttail -n 1 /etc/crontab | sudo tee /path/to/file >/dev/null
ctrl-alt-delor

Câu trả lời:


22

Dòng crontab của bạn có một hoặc nhiều dấu sao *trong đó, cho biết "bất cứ lúc nào". Khi dòng đó được thay thế từ thay thế lệnh, kết quả là một cái gì đó như

echo * * * * * cmd > /path/to/file

Mặc dù hầu hết các mở rộng hơn nữa không được áp dụng cho đầu ra của lệnh thay thế, mở rộng tên đường dẫn (như là tách trường) :

Các kết quả thay thế lệnh sẽ không được xử lý để mở rộng dấu ngã, mở rộng tham số, thay thế lệnh hoặc mở rộng số học. Nếu thay thế lệnh xảy ra bên trong dấu ngoặc kép, việc tách trường và mở rộng tên đường dẫn sẽ không được thực hiện trên kết quả của sự thay thế.

Mở rộng tên đường dẫn là những gì biến *.txtthành một danh sách tên tệp phù hợp (globalbing), trong đó *khớp với mọi thứ. Kết quả cuối cùng là bạn nhận được mọi tên tệp (không bị ẩn) trong thư mục làm việc được liệt kê cho mỗi *trong dòng crontab của bạn.


Bạn có thể khắc phục điều này bằng cách trích dẫn việc mở rộng, nếu mã bạn đã đăng là đại diện cho một lệnh phức tạp hơn:

sudo bash -c 'echo "$(tail -n 1 /etc/crontab)" > /path/to/file'

nhưng đơn giản hơn là chỉ mất echohoàn toàn:

sudo bash -c 'tail -n 1 /etc/crontab > /path/to/file'

Điều này sẽ làm những gì bạn muốn và nó cũng đơn giản hơn (sự khác biệt duy nhất về vật liệu là phiên bản này sẽ bỏ qua việc tách trường nếu không sẽ xảy ra, do đó, các khoảng trống sẽ không bị thu gọn).


5
Vì / etc / crontab hầu như luôn có thể đọc được trên thế giới, nên tất cả các mánh khóe "bash -c" thực sự không cần thiết: tail -n -1 /etc/crontab | sudo tee /path/to/filelà thành ngữ mà tôi thấy là ít bị lỗi nhất khi chuyển hướng đầu ra vào các tệp yêu cầu đặc quyền siêu người dùng.
Bass

5

Hãy xem xét một thư mục với các tệp này:

$ ls
crontab  file1  file2  file3
$ cat crontab
f*

Bây giờ, hãy chạy lệnh đuôi:

$ tail -n 1 crontab
f*

Trên đây là dòng cuối cùng crontabvà đây là những gì chúng ta mong đợi. Tuy nhiên:

$ echo $(tail -n 1 crontab)
file1 file2 file3

Dấu ngoặc kép loại bỏ vấn đề này:

$ echo "$(tail -n 1 crontab)"
f*

Không có dấu ngoặc kép, kết quả của sự thay thế lệnh được mở rộng bằng shell. Một trong những mở rộng là mở rộng tên đường dẫn . Trong trường hợp trên, điều này có nghĩa f*là được mở rộng để khớp với mọi tên tệp bắt đầu bằng f.

Trừ khi bạn rõ ràng muốn mở rộng shell, hãy đặt tất cả các biến shell của bạn và / hoặc thay thế lệnh trong dấu ngoặc kép.


4

mecanism vỏ ảm đạm sẽ mở rộng *đến tập tin địa phương.

dòng crontab có khả năng có một *giữ chỗ cho bất kỳ.

ví dụ: dòng này trong crontab chạy vào 7,47 sáng vào chủ nhật, ngôi sao đầu tiên có nghĩa là bất kỳ ngày nào, thứ hai bất kỳ tháng nào.

47  7 * * 0 /run/on/sunday

sau đó bạn tail, và vấn đề

echo 47  7 * * 0 /run/on/sunday

Điều đó sẽ mở rộng *sang tập tin cục bộ.

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.