Làm thế nào để sử dụng lệnh find để liệt kê tên tệp nhưng không có đường dẫn?
Tôi đã kiểm tra một số câu trả lời trực tuyến, nhưng chúng không hoạt động khi có một -name
tham số trong lệnh (có thể tôi đang làm sai điều gì đó, không chắc chắn). Những gì tôi muốn làm là chỉ liệt kê các tên tệp (không phải thư mục / đường dẫn) và phức tạp hơn, tôi có cùng một tên tệp với phần mở rộng khác nhau, vì vậy tôi cần lọc kết quả bằng cách sử dụng -name
và -o
, vấn đề là các đề xuất mà tôi đã thấy sử dụng hoặc -printf
hoặc basename
, và những thứ đó không hoạt động tốt khi có -name *.txt -o name *.pdf
. Có cách nào khác để giải quyết vấn đề này không?
Ví dụ về các tệp của tôi:
/dir1/dir2/dir3/dir4/
/file1.txt
/file1.pdf
/file1.ods ...etc.
Tôi chỉ quan tâm đến việc liệt kê một hoặc nhiều loại tệp cho mỗi danh sách (bằng cách sử dụng -name
để lọc kết quả của tôi.
Có thể thực hiện được nó chỉ bằng 1 find
lệnh hay tôi phải thực hiện 2 bước (lưu kết quả vào tệp tạm thời, sau đó lọc / tách thư mục khỏi tệp tạm thời)? Kết quả mà tôi đang cố gắng hoàn thành là một tệp văn bản có tên tệp trên mỗi dòng:
file1.txt
file1.pdf
file1.ods
file2.txt
file2.pdf
etc.
Lệnh tôi đang sử dụng là
find /dir1/dir2/dir3/dir4/ -type f -name '*.txt' -o -name '*.pdf' -o -name '*.ods' -printf "%f\n"
Tôi đang sử dụng GNU find.
Cập nhật
Hóa ra tôi phải đặt \(...\)
, như được nhắc bởi αғsнιη
Trả lời
Khi sử dụng nhiều biểu thức trong chế độ OR logic, -o
bạn cần đặt tất cả chúng bên trong \( ... \)
, nếu không, kết quả biểu thức cuối cùng luôn được tôn trọng; và -printf '%f\n'
được sử dụng để in tên tệp chỉ khi xóa bất kỳ thư mục hàng đầu nào.
find . -type f \( -name '*.pdf' -o -name '*.txt' \) -printf '%f\n'
thấy man finddưới OPERATORS phần về ( expr )
:
ĐIỀU HÀNH
...(expr) Quyền
ưu tiên. Vì dấu ngoặc đơn là đặc biệt đối với shell, thông thường bạn sẽ cần phải trích dẫn chúng.
vì vậy bạn có thể sử dụng \( ... \)
hoặc '(' ... ')'
(khoảng trắng sau và trước dấu ngoặc đơn là quan trọng) để thoát khỏi chúng.
Như đã được đề cập, bạn cần phải nhóm các -name
bài kiểm tra của mình trong ngoặc đơn. Các dấu ngoặc đơn này cần được thoát ra dưới dạng \( ... \)
hoặc được trích dẫn như ví dụ '(' ... ')'
để bảo vệ chúng khỏi shell (nơi mà chúng sẽ chỉ định một shell con).
Sử dụng tiêu chuẩn find
và cũng làm cho việc xử lý các hậu tố tên tệp dễ dàng hơn một chút:
set -- txt pdf ods
for suffix do
set -- "$@" -o -name "*.$suffix"
shift
done
shift
find /dir1/dir2/dir3/dir4 \( "$@" \) -type f -exec basename {} \;
Điều này đầu tiên đặt các tham số vị trí vào danh sách các hậu tố tên tệp mà chúng tôi muốn xem (điều này cũng có thể được lấy từ dòng lệnh nếu đây là một tập lệnh) và xây dựng danh sách OR của các -name
bài kiểm tra. Điều này sau đó được sử dụng trong find
dòng lệnh.
Càng find
lệnh riêng của mình sau đó gọi các basename
tiện ích cho mỗi tên được tìm thấy.
Thay vào đó, chúng ta có thể sử dụng thay thế tham số để loại bỏ tất cả trừ thành phần tên tệp của mỗi tên đường dẫn, nhưng để làm như vậy, chúng ta phải chuyển tên đường dẫn vào một sh -c
tập lệnh nội tuyến :
# [...] as before [...]
find /dir1/dir2/dir3/dir4 \( "$@" \) -type f -exec sh -c '
for pathname do
printf "%s\n" "${pathname##*/}"
done' sh {} +
Tôi hy vọng điều này sẽ chạy nhanh hơn so với biến thể bằng cách sử dụng basename
, ít nhất là nếu có nhiều tên tệp cần xử lý, mặc dù với GNU basename
từ coreutils, bạn có thể sử dụng -a
hoặc --multiple
thích như vậy:
find /dir1/dir2/dir3/dir4 \( "$@" \) -type f -exec basename -a {} +
Điều này sẽ gọi basename
càng ít lần càng tốt. Nhưng một lần nữa, nếu bạn đã cài đặt coreutils, bạn cũng có thể có findutils, với GNU find
, và có thể sử dụng -printf '%f\n'
để làm điều tương tự.