TL; DR: Nếu bạn chỉ ở đây để có câu trả lời đúng nhất, có lẽ bạn muốn sở thích cá nhân của tôi, find . -name '*.txt' -exec process {} \;
(xem phần dưới của bài đăng này). Nếu bạn có thời gian, hãy đọc qua phần còn lại để xem một số cách khác nhau và các vấn đề với hầu hết chúng.
Câu trả lời đầy đủ:
Cách tốt nhất phụ thuộc vào những gì bạn muốn làm, nhưng đây là một vài lựa chọn. Miễn là không có tệp hoặc thư mục nào trong cây con có khoảng trắng trong tên của nó, bạn chỉ có thể lặp qua các tệp:
for i in $x; do # Not recommended, will break on whitespace
process "$i"
done
Tốt hơn một chút, cắt bỏ biến tạm thời x
:
for i in $(find -name \*.txt); do # Not recommended, will break on whitespace
process "$i"
done
Nó là tốt hơn nhiều để toàn cầu khi bạn có thể. Không gian trắng an toàn cho các tệp trong thư mục hiện tại:
for i in *.txt; do # Whitespace-safe but not recursive.
process "$i"
done
Bằng cách bật globstar
tùy chọn, bạn có thể toàn cầu hóa tất cả các tệp phù hợp trong thư mục này và tất cả các thư mục con:
# Make sure globstar is enabled
shopt -s globstar
for i in **/*.txt; do # Whitespace-safe and recursive
process "$i"
done
Trong một số trường hợp, ví dụ: nếu tên tệp đã có trong một tệp, bạn có thể cần phải sử dụng read
:
# IFS= makes sure it doesn't trim leading and trailing whitespace
# -r prevents interpretation of \ escapes.
while IFS= read -r line; do # Whitespace-safe EXCEPT newlines
process "$line"
done < filename
read
có thể được sử dụng an toàn kết hợp với find
bằng cách đặt dấu phân cách phù hợp:
find . -name '*.txt' -print0 |
while IFS= read -r -d '' line; do
process "$line"
done
Đối với các tìm kiếm phức tạp hơn, có thể bạn sẽ muốn sử dụng find
, với -exec
tùy chọn của nó hoặc với -print0 | xargs -0
:
# execute `process` once for each file
find . -name \*.txt -exec process {} \;
# execute `process` once with all the files as arguments*:
find . -name \*.txt -exec process {} +
# using xargs*
find . -name \*.txt -print0 | xargs -0 process
# using xargs with arguments after each filename (implies one run per filename)
find . -name \*.txt -print0 | xargs -0 -I{} process {} argument
find
cũng có thể cd vào thư mục của mỗi tệp trước khi chạy lệnh bằng cách sử dụng -execdir
thay vì -exec
và có thể được thực hiện tương tác (nhắc trước khi chạy lệnh cho mỗi tệp) bằng cách sử dụng -ok
thay vì -exec
(hoặc -okdir
thay vì -execdir
).
*: Về mặt kỹ thuật, cả hai find
và xargs
(theo mặc định) sẽ chạy lệnh với càng nhiều đối số càng tốt trên dòng lệnh, bao nhiêu lần để vượt qua tất cả các tệp. Trong thực tế, trừ khi bạn có số lượng tệp rất lớn, điều đó sẽ không thành vấn đề và nếu bạn vượt quá độ dài nhưng cần tất cả chúng trên cùng một dòng lệnh, thì bạn sẽ tìm thấy một cách khác.