Làm cách nào tôi có thể sử dụng hai lệnh bash trong -exec của lệnh find?


32

Có thể sử dụng 2 lệnh trong -execphần findlệnh?

Tôi đã thử một cái gì đó như:

find . -name "*" -exec  chgrp -v new_group {}  ; chmod -v 770 {}  \;

va tôi lây:

find: thiếu đối số cho -exec
chmod: không thể truy cập {}: Không có tệp hoặc thư mục như vậy
chmod: không thể truy cập ;: Không có tệp hoặc thư mục như vậy

Câu trả lời:


44

Đối với findlệnh, bạn cũng có thể chỉ cần thêm nhiều -execlệnh liên tiếp:

find . -name "*" -exec chgrp -v new_group '{}' \; -exec chmod -v 770 '{}' \;

Lưu ý rằng lệnh này, trong kết quả của nó, tương đương với việc sử dụng

tệp chgrp -v new_group && chmod -v 770

trên mỗi tập tin.

Tất cả các findthông số 's như -name, -exec, -sizevà như vậy, thực sự thử nghiệm : findsẽ tiếp tục chạy từng cái một chừng nào toàn bộ chuỗi cho đến nay đã đánh giá để đúng . Vì vậy, mỗi -execlệnh liên tiếp chỉ được thực hiện nếu các lệnh trước trả về true (nghĩa là 0trạng thái thoát của các lệnh). Nhưng findcũng hiểu các toán tử logic như hoặc ( -o) chứ không phải ( !). Do đó, để sử dụng một chuỗi các -execthử nghiệm bất kể kết quả trước đó, người ta sẽ cần sử dụng một cái gì đó như thế này:

find . -name "*" \( -exec chgrp -v new_group {} \; -o -exec chmod -v 770 {} \; \)

4
+1: Vâng, đó là cách thanh lịch nhất để làm điều đó. Nếu bạn có thể giải thích, tại sao bạn sử dụng '{}'(dấu nháy quanh niềng răng), vui lòng truy cập: unix.stackexchange.com/q/8647/4485
người dùng không xác định

1
@user Thật không may, tôi không biết nếu nó vẫn cần thiết. Tôi đã làm một số thử nghiệm vừa rồi và không gặp phải tình huống nó sẽ thay đổi bất cứ điều gì. Tôi đoán đó chỉ là "thực hành tốt" sẽ chết.
rozcietrzewiacz

2
Các trích dẫn rất quan trọng đối với các tệp có khoảng trắng trong tên của chúng.
ness101

17
find . -name "*" -exec sh -c 'chgrp -v new_group "$0" ; chmod -v 770 "$0"' {} \;

@Gilles: Sự kỳ diệu của việc -cxử lý kỳ lạ 0 đô la khiến tôi nghĩ rằng điều này là sai mỗi khi tôi liếc nhìn nó, nhưng nó hoàn toàn chính xác.
derobert

Tôi thích cái vỏ rõ ràng được định nghĩa ...
djangofan

Câu trả lời này (và câu trả lời của Giles) có vẻ như là câu trả lời tốt hơn cho câu hỏi được đưa ra sh -c.

14

Lệnh của bạn trước tiên được phân tách bằng shell thành hai lệnh được phân tách bằng a ;, tương đương với một dòng mới:

find . -name "*" -exec chgrp -v new_group {}
chmod -v 770 {} \;

Nếu bạn muốn chạy lệnh shell, hãy gọi shell một cách rõ ràng bằng bash -c(hoặc sh -cnếu bạn không quan tâm rằng shell đó là bash cụ thể):

find . -name "*" -exec sh -c 'chgrp -v new_group "$0"; chmod -v 770 "$0"' {} \;

Lưu ý việc sử dụng {}như là một đối số cho shell; đó là đối số zeroth (thường là tên của shell hoặc script, nhưng điều này không quan trọng ở đây), do đó được tham chiếu là "$0".

Bạn có thể chuyển nhiều tên tệp vào shell cùng một lúc và làm cho shell lặp qua chúng, nó sẽ nhanh hơn. Ở đây tôi chuyển _như tên tập lệnh và các đối số sau đây là tên tệp, mà for x(một phím tắt cho for x in "$@") lặp lại.

find . -name "*" -exec sh -c 'for x; do chgrp -v new_group "$x"; chmod -v 770 "$x"; done' _ {} +

Lưu ý rằng vì bash 4 hoặc trong zsh, bạn không cần tìm ở đây. Trong bash, hãy chạy shopt -s globstar(đặt nó vào trong của bạn ~/.bashrc) để kích hoạt **/trạng thái đứng cho một thư mục đệ quy toàn cầu. (Trong zsh, điều này luôn hoạt động.) Sau đó

chgrp -v new_group -- **/*; chmod -v 770 -- **/*

hoặc nếu bạn muốn các tệp được lặp theo thứ tự

for x in **/*; do
  chgrp -v new_group -- "$x"
  chmod -v 770 -- "$x"
done

Một điểm khác biệt với findlệnh là shell bỏ qua các tệp chấm (các tệp có tên bắt đầu bằng a .). Để bao gồm chúng, trong bash, bộ đầu tiên GLOBIGNORE=.:..; trong zsh, sử dụng **/*(D)như mô hình toàn cầu.


Câu trả lời này (và câu trả lời của Glenn) có vẻ như là câu trả lời tốt hơn cho câu hỏi được đưa ra sh -c.
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.