$ find -exec cd => đưa ra lỗi: => find: 'cd': Không có tệp hoặc thư mục như vậy


8

Khi tôi chạy lệnh này, nó hoạt động:

$ find . -inum 888696 -exec ls '{}' \;
Conversation.pst  Outlook Data File  Outlook Data File.sbd  Trash      Unsent Messages
Inbox.pst     Outlook Data File.msf  Sent.pst       Trash.msf  Unsent Messages.msf

Tuy nhiên, khi thay thế lsbằng cdkhông hoạt động:

$ find . -inum 888696 -exec cd '{}' \;
find: cd’: No such file or directory

Tôi biết cdlà một tích bashhợp sẵn, vì vậy tôi đã thử cái này cũng không hoạt động:

$ find . -inum 888696 -exec builtin cd '{}' \;
find: builtin’: No such file or directory

Làm thế nào tôi có thể sử dụng cdcùng với find -execlệnh?


CẬP NHẬT

Lý do tôi đang cố gắng để sử dụng cdvới find -execlà tên thư mục là một trong những kỳ lạ mà các chương trình trên thiết bị đầu cuối của tôi như là một cái gì đó giống như ????.


1
BTW, bạn có thể LC_ALL=C printf '%q\n' *in tên ASCII cho tất cả các tệp trong thư mục hiện tại của bạn, từ một đến một dòng (thay đổi dòng mới thành $'\n'hoặc tương tự).
Charles Duffy

Câu trả lời:


15

Các -exectùy chọn để findthực thi một tiện ích bên ngoài, có thể có một số tùy chọn dòng lệnh và đối số khác.

Unix của bạn không cung cấp cdnhư một tiện ích bên ngoài, chỉ là một vỏ được tích hợp sẵn, do đó findkhông thể thực thi nó. Ít nhất hệ điều hành MacOS và Solaris làm cung cấp cdnhư một tiện ích bên ngoài.

Sẽ có ít hoặc không sử dụng để thực thi cdtheo cách này, ngoại trừ như một cách kiểm tra xem tên đường dẫn được tìm thấy có phải findlà một thư mục mà bạn có thể truy cập được không cd. Thư mục làm việc trong shell tương tác của bạn (hoặc bất cứ điều gì đang gọi find) sẽ không thay đổi.

Liên quan:


Nếu bạn gặp vấn đề với tên thư mục lạ hoặc cực kỳ khó nhập và bạn muốn thay đổi vào thư mục đó, thì hãy xem xét việc tạo một liên kết tượng trưng đến thư mục và sau đó cdvào liên kết đó bằng cách sử dụng liên kết đó:

find . -inum 888696 -exec ln -s {} thedir ';'

Điều này sẽ tạo ra một liên kết tượng trưng có tên thedirsẽ trỏ đến thư mục có vấn đề. Sau đó, bạn có thể thay đổi thư mục làm việc với

cd thedir

(nếu liên kết tồn tại trong thư mục hiện tại). Điều này tránh sửa đổi thư mục theo bất kỳ cách nào. Một ý tưởng khác là đổi tên thư mục theo cách tương tự find, nhưng điều đó sẽ không được khuyến khích nếu một chương trình khác mong muốn thư mục có tên cụ thể đó.


Lý do tôi ý định sử dụng cdvới find -execđó là tên thư mục là trong một số ký tự lạ mà không hiển thị đúng trên thiết bị đầu cuối của tôi.
dùng3405291

@ user3405291 Không rõ câu hỏi bạn mong đợi điều gì sẽ xảy ra khi bạn chạy lệnh. Bạn có muốn thay đổi thư mục trong vỏ tương tác?
Kusalananda

Có, tôi chỉ muốn cdvào một thư mục có tên xấu và tôi không thể cdvào đó theo cách thông thường.
dùng3405291

@ user3405291 Xem cập nhật.
Kusalananda

Điều thú vị là đó /bin/cdlà kết quả của POSIX ( pubs.opengroup.org/onlinepub/9699919799/utilities/ mẹo ) trong đó các nội dung thông thường phải có thể truy cập được để thực thi (). Tất nhiên, /bin/cdcó khả năng không làm những gì mọi người muốn :-)
Stephen Harris

7

findtự chạy -execlệnh, nó không liên quan đến trình bao. Ngay cả nếu có, việc thay đổi thư mục sẽ chỉ tồn tại cho đến khi lớp vỏ đó thoát ra, ngay sau khi cd.

Bạn sẽ cần phải lấy tên tệp ra vỏ hiện tại để cdvào nó. Tùy thuộc vào mức độ xấu của tên tệp của bạn, bạn có thể sử dụng thay thế lệnh:

cd "$(find . -inum 888696)"

Điều đó sẽ không hoạt động nếu tên tệp kết thúc trong một dòng mới, vì sự thay thế lệnh ăn các dòng mới. Trong trường hợp đó, bạn cần bảo vệ dòng mới và loại bỏ phần findbổ sung khi in:

dir=$(find . -inum 888696; echo x)
cd "${dir%?x}"

Hoặc, với GNU find, nó không in dòng mới (nhưng vẫn bảo vệ bất kỳ trong tên tệp):

dir=$(find . -inum 888696 -printf "%px" -quit)
cd "${dir%x}"

Đồng thời sử dụng biến -quitvị ngữ (cũng là phần mở rộng GNU), để ngừng tìm kiếm kết quả khớp đầu tiên dưới dạng tối ưu hóa.

Ngoài ra, bạn có thể bắt đầu một lớp vỏ mới từ bên trong find, nhưng nó hơi xấu:

find . -inum 888696 -exec bash -c 'cd "$1" && exec bash' sh {} \;

Đã thử mẹo của bạn với "echo x", trên các thư mục kết thúc bằng dòng mới, trả lại vận chuyển và cả hai, nhưng không thành công.
Gerard H. Pille

@ GerardH.Pille, oh, xin lỗi, tôi đã quên dòng mới findtự thêm khi in. Đã chỉnh sửa.
ilkkachu

Nếu bạn thay thế printf bằng print0, bạn có thể thực hiện 'cd "$ dir"'.
Gerard H. Pille

@ GerardH.Pille, có lẽ. Nhưng Bash bỏ qua bất kỳ byte nul nào trong đầu vào từ một lệnh thay thế và chỉ xóa dòng mới sau đó. Vì vậy, dir=$(find -print0)vẫn sẽ bỏ qua dòng mới của tên tệp ...
ilkkachu

5

Không phải với exec, nhưng điều này có thể đủ tốt cho bạn:

cd "$(find . -inum 888696 -type d)"

"-Depe d", chỉ để chắc chắn. Về những gì, tôi không thực sự biết.


Điều này không thành công nếu tên của thư mục kết thúc bằng một dòng mới.
Kusalananda

Chắc chắn, nhưng thư mục hiếm khi làm. Nếu tôi cố gắng tạo một cái trên ext4 linux, tôi sẽ gặp "lỗi giao thức". Bạn không nghĩ rằng điều này là một sự lãng phí thời gian?
Gerard H. Pille

2
Chà, tên hiếm khi có ký tự không thể in được, nhưng cái này rõ ràng là có.
Kusalananda

Hệ thống tập tin nào cho phép dòng mới trong tên thư mục?
Gerard H. Pille

1
@ GerardH.Pille, bạn đã kiểm tra điều đó như thế nào? mkdir $'foo\n'hoạt động hoàn hảo ở đây; Tôi vẫn chưa thấy một hệ thống tập tin UNIX gốc nơi nó không được hỗ trợ.
Charles Duffy

4

Sử dụng luồng được phân định bằng NUL để đọc đầu ra từ findđó hoạt động trong mọi trường hợp - bao gồm cả các tên kết thúc bằng dòng mới. Ngoài ra, bạn có thể sử dụng printf '%q'để tạo một đại diện dễ đọc của tên tệp.

inum=888696
if IFS= read -r -d '' filename < <(find . -inum "$inum" -print0); then
  LC_ALL=C printf 'Located filename: %q\n' "$filename" >&2
  cd -- "$filename"
else
  echo "No file located for inode $inum" >&2
fi

3

Nếu bạn nhận được thông báo này, thì nền tảng hệ điều hành của bạn bị lỗi. Tiêu chuẩn POSIX yêu cầu một lệnh có tên cdphải có sẵn trong hệ thống tệp để có thể được gọi thông qua exec().

Bây giờ là tin xấu cho bạn:

Ngay cả khi nền tảng hệ điều hành của bạn không có lỗi, bạn vẫn không thấy cảnh báo, nhưng bạn không nhận được kết quả như mong đợi, vì nó không giúp bạn nếu một chương trình riêng biệt thay đổi thư mục làm việc hiện tại và ngay lập tức chết sau đó.

Nếu bạn muốn có hiệu quả cdtrong một lệnh được thực thi bởi find, bạn có thể làm một cái gì đó như:

find . -type d -exec sh -c 'cd "$1"; some other command' dummy {} \;

2
Đó chỉ là một lỗi nếu nền tảng đó yêu cầu sự phù hợp POSIX. Có một tiện ích cd độc lập không phải là rất hữu ích, vì vậy sẽ tốt hơn nếu bạn bỏ qua yêu cầu đó mà không ảnh hưởng đến khả năng sử dụng của nền tảng. Lưu ý rằng việc để lại một mở rộng tham số không được trích dẫn có ý nghĩa rất đặc biệt sh, không phải là điều bạn muốn làm. Tốt hơn hết là tránh các giá trị giả cho tập lệnh nội tuyến $0đó, ví dụ như được sử dụng trong các thông báo lỗi (như khi điều đó cdsẽ thất bại).
Stéphane Chazelas

Ý bạn là cd "$1"sao Nếu tên khó gõ, nó cũng có thể chứa các siêu ký tự vỏ ...
Toby Speight

đúng đây là một lỗi đánh máy
schily
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.