Làm cách nào để sử dụng `find` để đi đến thư mục của tệp đó


11

Tôi muốn tìm một tập tin và sau đó vào thư mục chứa nó. Tôi đã thử find /media/storage -name "Fedora" | xargs cdnhưng tất nhiên, tôi is not a directorylỗi.

Làm cách nào để vào thư mục mẹ của nó bằng lệnh một dòng?


1
Và nếu có nhiều tệp từ nhiều vị trí thì sao?
Sergiy Kolodyazhnyy

@Serg Tôi đang tìm kiếm tệp Fedora * .iso và tôi biết chỉ có một. Nếu có nhiều hơn thì nó sẽ vào direcotry đầu tiên, tôi đoán
Hrvoje T

Trong bash với shopt -s globstar, bạn có thể cd /media/storage/**/Fedora, nhưng điều đó không dừng đánh giá toàn cầu ở trận đấu đầu tiên (vì vậy nó chậm hơn giải pháp của Steeller. Để sử dụng tương tác, những gì tôi thường làm là với chuột và sao chép / dán tên thư mục, (và alt + backspace khi cần để loại bỏ các thành phần đường dẫn mà tôi không muốn), nhưng nếu bạn làm điều này nhiều thì tôi đoán một hàm shell có thể đáng để thực hiện.
Peter Cordes

1
BTW, xargs cdkhông thể làm việc. cdchỉ có thể hoạt động như một shell dựng sẵn, bởi vì nó phải sửa đổi bối cảnh của chính shell. Không có cách nào một xargsquá trình trẻ em có thể làm điều đó. IDK nếu đó là những gì bạn có nghĩa là "tất nhiên", hoặc nếu đường dẫn findin có chứa khoảng trắng, được phân chia bởi xargs kể từ khi bạn không sử dụng -d \nhoặc bất cứ điều gì. Hoặc find -exec {} \;.
Peter Cordes

lưu ý: bạn không thể chạy cdnhư vậy cdlà một bash được xây dựng, nếu cdlà một lệnh riêng biệt, thì nó sẽ thay đổi thư mục (của chính nó), và sau đó thoát (trả bạn về shell, ở trạng thái như trước, không thay đổi dir).
ctrl-alt-delor

Câu trả lời:


14

Ít nhất nếu bạn có GNU find, bạn có thể sử dụng -printf '%h'để lấy thư mục

       %h     Leading directories of file's name (all but the last ele‐
              ment).  If the file name contains no slashes (since it is
              in  the  current  directory)  the %h specifier expands to
              ".".

Vì vậy, bạn có thể có thể làm

cd "$(find /media/storage -name "Fedora" -printf '%h' -quit)"

Các -quitcần ngăn chặn nhiều đối số cdtrong trường hợp nhiều hơn một tập tin phù hợp.


1
-quitcũng không nhất thiết phải được hỗ trợ. Trong NetBSD, nó được gọi -exit, xem unix.stackexchange.com/a/62883/117599
phk

2
Nếu không có printf bạn có thể làm -exec dirname thay thế?
Chàng trai

@Guy ý tưởng tốt vâng, nghe có vẻ như nó cũng nên hoạt động
Steeldo

6

Tương tự như giải pháp của Steeldo nhưng sử dụng -execdir(nếu bạn findhỗ trợ nó, như của GNU hoặc FreeBSD find) kết hợp với pwd:

cd "$(find /media/storage -name "Fedora" -execdir pwd \; -quit)"

-quitlà tùy chọn trong trường hợp chỉ có một kết quả duy nhất và thu thập dữ liệu toàn bộ thư mục không có vấn đề gì. Trên NetBSD, nó -exitvà trên OpenBSD, nó không tồn tại.


\;để làm gì?
Hrvoje T

1
@HrvojeT Giống như -execnó nói findvề sự kết thúc của các tham số cho lệnh thực thi. Nhưng vì chúng tôi muốn gọi pwdmà không có tham số ở đây, chúng tôi đặt \;ngay sau nó.
phk

Có bất kỳ findtriển khai nào hỗ trợ execdir nhưng không -printf %h? Có vẻ như không thể với tôi. Thật không may, không ai được POSIX yêu cầu: /
Peter Cordes

1
@PeterCordes FreeBSD's find: freebsd.org/cgi/man.cgi?find%281%29 (Chỉ cần xác nhận nó trên bản cài đặt FreeBSD 11.)
phk

@PeterCordes Tương tự cho NetBSD ( netbsd.gw.com/cgi-bin/man-cgi?find++NetBSD-c Hiện ) và OpenBSD ( man.openbsd.org/OpenBSD-cản/man1/find.1 ). Latter không hỗ trợ -quit/ -exitmặc dù.
phk

5

Bạn có thể thực hiện tìm chạy một shell mới trong thư mục mà nó tìm thấy.

exec find /media/storage -name "Fedora" -execdir "$SHELL" \;

, sau đó thư mục hiện tại sẽ là thư mục có tệp Fedora trong đó. ;)

Rõ ràng điều này chỉ làm một cái gì đó giống như những gì bạn muốn nếu bạn đang gõ các lệnh tương tác.


4

Với zsh:

cd /media/storage/**/Fedora([1]:h)

để cdvào thư mục đầu tiên (theo thứ tự chữ cái) có chứa một tập tin gọi Fedora.

  • **: bất kỳ cấp độ thư mục nào (các thư mục ẩn được bỏ qua theo mặc định, sử dụng Dvòng loại toàn cầu để bao gồm chúng)
  • [1]: chỉ người đầu tiên
  • :h: sửa đổi đầu : lấy dirname.

Trái ngược với cd "$(find ...)", nó cũng hoạt động nếu tên thư mục kết thúc bằng ký tự dòng mới. Một lợi thế khác là bạn sẽ nhận được thông báo lỗi không khớp khi không có thư mục phù hợp (trong khi hầu hết các shell cd ""sẽ không làm gì âm thầm).

Một nhược điểm là nó sẽ bò toàn bộ /media/storagetrước khi trở về.


Trong bash, cdvới nhiều đối số chỉ nhìn vào đối số đầu tiên, do đó cd $(dirname /media/storage/**/Fedora)sẽ hoạt động (với shopt -s globstar) nếu không có khoảng trắng trong đường dẫn. Để có được trích dẫn chính xác, tôi nghĩ rằng một mảng bash là dễ nhất : target=(/media/storage/**/Fedora); cd "${target%/*}". Nhưng tại thời điểm đó, sẽ nhanh hơn khi sử dụng chuột để sao chép / dán tìm đầu ra thay vì tương tác với nó.
Peter Cordes

2
@PeterCordes, nhiều dirnametriển khai sẽ không chấp nhận nhiều hơn một đối số. Lưu ý rằng đó không phải là khoảng trắng , đó là bất kỳ ký tự nào hiện có trong $IFS( khoảng trắng , tab và dòng mới theo mặc định) và các ký tự đại diện. Lưu ý rằng cho dù bash's cdsẽ chấp nhận nhiều hơn một đối số phụ thuộc vào cách nó được biên dịch ( CD_COMPLAINStrong config-top.h). Người ta có thể tưởng tượng rằng các phiên bản trong tương lai bashcuối cùng cũng sẽ thực hiện tính năng hai arg như trong zsh.
Stéphane Chazelas

Cảm ơn. Tôi chỉ nhìn vào trang chủ dirname GNU coreutils. Phiên bản dirname là khủng khiếp; Tôi chỉ đề cập đến nó như một cái gì đó bạn có thể thử tương tác trong trường hợp nó hoạt động. Phiên bản dựa trên mảng của tôi không gặp phải bất kỳ vấn đề nào trong số đó, vì chỉ "${target%*/}"mở rộng thành phần tử mảng đầu tiên ( /Fedorabị tước). Tôi nghĩ rằng phiên bản đó hoàn toàn mạnh mẽ chống lại bất kỳ nhân vật có thể có trong tên đường dẫn.
Peter Cordes
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.