Làm cách nào để tìm tệp trong thư mục con và sắp xếp chúng theo tên tệp trong một lệnh?


9

Kết quả của một tìm kiếm bình thường bằng cách sử dụng find . ! -path "./build*" -name "*.txt":

./tool/001-sub.txt
./tool/000-main.txt
./zo/001-int.txt
./zo/id/002-and.txt
./as/002-mod.txt

và khi được sắp xếp với sort -n:

./as/002-mod.txt
./tool/000-main.txt
./tool/001-sub.txt
./zo/001-int.txt
./zo/id/002-and.txt

tuy nhiên đầu ra mong muốn là:

./tool/000-main.txt
./zo/001-int.txt
./tool/001-sub.txt
./zo/id/002-and.txt
./as/002-mod.txt

có nghĩa là đầu ra được sắp xếp chỉ dựa trên tên tệp , nhưng thông tin thư mục nên được duy trì như một phần của đầu ra.

Chỉnh sửa : Làm cho ví dụ phức tạp hơn vì cấu trúc thư mục con có thể bao gồm nhiều cấp.


2
Xem câu hỏi này tôi đã hỏi trên SO: stackoverflow.com/questions/3222810/ từ
camh

@camh - nếu có thể tôi chỉ muốn sử dụng các lệnh unix. Trong mọi trường hợp, câu hỏi của tôi gần như là một bản sao của bạn. Bạn có thể chuyển giải pháp tốt nhất cho chủ đề này (giữ một liên kết đến các bản gốc) để tôi có thể đánh dấu là giải pháp không?
giải mã

Nếu @Shawn thực hiện các thay đổi tôi đã đề xuất trong nhận xét của mình (sử dụng -printfthay vì awk), tôi nghĩ đó là giải pháp tốt nhất. Tôi đã làm lại việc thực hiện ban đầu của mình để sử dụng phương pháp này.
camh

Câu trả lời:


9

Bạn cần sắp xếp theo trường cuối cùng (xem xét /như một dấu tách trường). Thật không may, tôi không thể nghĩ ra một công cụ có thể làm điều này khi số lượng trường thay đổi (nếu chỉ sort -kcó thể lấy giá trị âm).

Để giải quyết vấn đề này, bạn sẽ phải thực hiện một cách trang trí sắp xếp. Đó là, lấy tên tệp và đặt nó ở đầu theo sau là dấu phân cách trường, sau đó thực hiện sắp xếp, sau đó xóa cột đầu tiên và dấu tách trường.

find . ! -path "./build*" -name "*.txt" |\
    awk -vFS=/ -vOFS=/ '{ print $NF,$0 }' |\
    sort -n -t / |\
    cut -f2- -d/

awkLệnh đó cho biết dấu phân cách trường FS được đặt thành /; điều này ảnh hưởng đến cách nó đọc các lĩnh vực. Dấu tách trường đầu ra OFS cũng được đặt thành /; Điều này ảnh hưởng đến cách in hồ sơ. Câu lệnh tiếp theo cho biết in cột cuối cùng ( NFlà số trường trong bản ghi, do đó, nó cũng là chỉ mục của trường cuối cùng) cũng như toàn bộ bản ghi ( $0là toàn bộ bản ghi); nó sẽ in chúng với OFS giữa chúng. Sau đó, danh sách là sorted, xử lý /như dấu tách trường - vì chúng ta có tên tệp đầu tiên trong bản ghi, nó sẽ sắp xếp theo đó. Sau đó, các cutbản in chỉ có các trường từ 2 đến hết, một lần nữa được coi /là dấu tách trường.


3
Vì đây là với find (1), bạn có thể bỏ qua phần awk và sử dụng-printf '%f/%p\n'
camh

thực sự thiết lập của chúng tôi phức tạp hơn một chút. Nó bao gồm độ sâu subir biến. Chỉnh sửa câu hỏi để phản ánh thực tế này. Tôi xin lỗi vì không bao gồm điều này lúc đầu.
giải mã

1
@Unode: Giải pháp của Shawn xử lý độ sâu biến tốt, đó là giải pháp chuẩn cho vấn đề này (tối đa các biến thể nhỏ).
Gilles 'SO- ngừng trở nên xấu xa'

4

Tôi sẽ sử dụng các tệp '-printf' để xuất tên và đường dẫn, sắp xếp theo tên và cắt tên ở bước cuối cùng. '###' chỉ là một điểm đánh dấu, để giúp cắt.

find -name "*.txt" -printf "%f###%p\n" | sort -n | sed 's/.*###//'

% f in tên tệp,% p toàn bộ đường dẫn.

Tôi đã đơn giản hóa lệnh find để đưa nó vào một dòng, tất nhiên bạn sẽ rời khỏi ! -path "./build*"phần đó.


3

Trong zsh ≥4.3.10:

print -l -- **/*.txt~build*(oe\''REPLY=${REPLY:t}'\')
  • **/*.txtphù hợp *.txttrong thư mục hiện tại và thư mục con của nó đệ quy .
  • ~build* loại trừ các kết quả khớp có văn bản bắt đầu bằng build*(như ! -path './build*'). (Bạn cần setopt extended_globđầu tiên.)
  • (oe\''…'\')là một vòng loại toàn cầu sắp xếp . REPLY=…xây dựng chuỗi để sắp xếp từ chuỗi để trả về.
  • ${REPLY:t}tên cơ sở (đường đuôi đuôi) của đường dẫn.

Rất nhiều phép thuật kết hợp. Thú vị nhưng chúng tôi giới hạn ở cú pháp sh. +1
giải mã
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.