$ find -exec cd => memberikan kesalahan: => find: 'cd': Tidak ada file atau direktori seperti itu

8

Ketika saya menjalankan perintah ini berfungsi:

$ 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

Namun, Saat mengganti lsdengan cditu tidak berfungsi:

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

Saya tahu cdadalah bashbuilt-in, jadi saya mencoba ini yang tidak berhasil:

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

Bagaimana cara menggunakan cdbersama dengan find -execperintah?


MEMPERBARUI

Alasan saya mencoba untuk menggunakan cddengan find -execadalah bahwa nama direktori adalah aneh yang menunjukkan pada terminal saya sebagai sesuatu seperti ????.

pengguna3405291
sumber
1
BTW, Anda bisa LC_ALL=C printf '%q\n' *mencetak nama ASCII untuk semua file di direktori Anda saat ini, satu ke satu baris (mengubah baris baru ke $'\n'atau serupa).
Charles Duffy

Jawaban:

15

The -execpilihan untuk findmengeksekusi sebuah utilitas eksternal, mungkin dengan beberapa opsi baris perintah dan argumen lainnya.

Unix Anda tidak menyediakan cdutilitas eksternal, hanya sebagai shell bawaan, jadi findgagal menjalankannya. Setidaknya MacOS dan Solaris jangan memberikan cdsebagai utilitas eksternal.

Akan ada sedikit atau tidak ada gunanya untuk mengeksekusi cddengan cara ini, kecuali sebagai cara untuk menguji apakah pathname ditemukan oleh findadalah direktori di mana Anda akan dapat cd. Direktori yang berfungsi di shell interaktif Anda (atau apa pun panggilan find) tidak akan berubah.

Terkait:


Jika Anda mengalami masalah dengan nama direktori yang aneh atau sangat sulit untuk diketik, dan Anda ingin mengubah ke direktori itu, maka pertimbangkan untuk membuat tautan simbolis ke direktori dan kemudian cdke dalamnya menggunakan tautan itu sebagai gantinya:

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

Ini akan membuat tautan simbolis bernama thediryang akan menunjuk ke direktori yang bermasalah. Anda kemudian dapat mengubah direktori kerja dengan

cd thedir

(jika tautan ada di direktori saat ini). Ini menghindari memodifikasi direktori dengan cara apa pun. Gagasan lain adalah mengubah nama direktori dengan cara yang sama find, tetapi itu tidak akan dianjurkan jika program lain mengharapkan direktori memiliki nama tertentu.

Kusalananda
sumber
Alasan saya maksud untuk menggunakan cddengan find -execadalah bahwa nama direktori dalam beberapa karakter aneh yang tidak muncul dengan benar pada terminal saya.
user3405291
@ user3405291 Tidak jelas dari pertanyaan apa yang Anda harapkan terjadi ketika Anda menjalankan perintah. Apakah Anda berharap untuk mengubah direktori di shell interaktif?
Kusalananda
Ya, saya hanya ingin cdmasuk ke direktori yang memiliki nama buruk , dan saya tidak bisa cdmelakukannya dengan cara biasa.
user3405291
@ user3405291 Lihat pembaruan.
Kusalananda
Yang lucu adalah itu /bin/cdadalah hasil dari POSIX ( pubs.opengroup.org/onlinepubs/9699919799/utilities/... ) di mana standar bawaan harus dapat diakses oleh exec (). Tentu saja, /bin/cdkemungkinan tidak melakukan apa yang diinginkan orang :-)
Stephen Harris
7

findmenjalankan -execperintah itu sendiri, itu tidak melibatkan shell. Bahkan jika itu terjadi, perubahan direktori hanya akan bertahan sampai shell itu keluar, segera setelah cd.

Anda harus memasukkan nama file ke shell saat ini cdke dalamnya. Bergantung pada seberapa buruk nama file Anda, Anda bisa menggunakan substitusi perintah:

cd "$(find . -inum 888696)"

Itu tidak akan berfungsi jika nama file berakhir di baris baru, karena penggantian perintah memakan baris baru. Dalam hal ini, Anda harus melindungi baris baru dan menyingkirkan yang findditambahkan saat mencetak:

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

Atau, dengan GNU find, mintalah agar ia tidak mencetak baris tambahan (tetapi masih melindungi nama file):

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

Juga menggunakan -quitpredikat (juga ekstensi GNU), untuk berhenti mencari pertandingan pertama sebagai pengoptimalan.

Atau, Anda dapat memulai shell baru dari dalam find, tapi agak jelek:

find . -inum 888696 -exec bash -c 'cd "$1" && exec bash' sh {} \;
ilkkachu
sumber
Coba trik Anda dengan "echo x", pada direktori yang diakhiri dengan baris baru, carriage return dan keduanya, tanpa hasil.
Gerard H. Pille
@ GerardH.Pille, oh, maaf, saya lupa findmenambahkan baris baru saat mencetak. Diedit.
ilkkachu
Jika Anda mengganti printf dengan print0, Anda dapat melakukan 'cd "$ dir"'.
Gerard H. Pille
@ GerardH.Pille, mungkin. Tapi Bash mengabaikan byte dalam input dari substitusi perintah, dan menghapus baris baru setelah itu. Jadi dir=$(find -print0)masih akan membuang baris baru dari nama file ...
ilkkachu
5

Tidak dengan exec, tetapi ini mungkin cukup baik untuk Anda:

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

"-Type d", hanya untuk memastikan. Tentang apa, saya tidak begitu tahu.

Gerard H. Pille
sumber
Ini gagal jika nama direktori berakhir dengan baris baru.
Kusalananda
Tentu, tetapi direktori jarang melakukannya. Jika saya mencoba membuat satu di linux ext4, saya mendapatkan "protokol error". Tidakkah menurut Anda ini buang-buang waktu?
Gerard H. Pille
2
Ya, nama jarang memiliki karakter yang tidak patut dicetak, tapi yang ini jelas.
Kusalananda
Sistem file apa yang memungkinkan baris baru dalam nama direktori?
Gerard H. Pille
1
@ GerardH.Pille, bagaimana Anda mengujinya? mkdir $'foo\n'bekerja dengan sempurna di sini; Saya belum melihat sistem file UNIX asli di mana itu tidak didukung.
Charles Duffy
4

Gunakan aliran yang dibatasi NUL untuk membaca keluaran dari findyang berfungsi di semua kasus - termasuk nama yang diakhiri dengan baris baru. Selain itu, Anda dapat menggunakan printf '%q'untuk menghasilkan representasi nama file yang dapat dibaca.

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
Charles Duffy
sumber
3

Jika Anda mendapatkan pesan ini, maka platform OS Anda bermasalah. Standar POSIX mengharuskan perintah yang bernama cdharus tersedia di sistem file sehingga dapat dipanggil via exec().

Sekarang berita buruk untuk Anda:

Bahkan jika platform OS Anda tidak bermasalah, Anda hanya tidak melihat peringatan, tetapi Anda tidak mendapatkan hasil yang Anda harapkan, karena itu tidak membantu Anda jika suatu program terpisah mengubah direktori kerjanya saat ini dan segera mati setelah itu.

Jika Anda ingin cdperintah yang efektif dijalankan oleh find, Anda dapat melakukan sesuatu seperti:

find . -type d -exec sh -c 'cd "$1"; some other command' dummy {} \;
schily
sumber
2
Itu hanya bug jika platform itu mengklaim kesesuaian POSIX. Memiliki utilitas cd mandiri tidak terlalu berguna, jadi masuk akal untuk mengabaikan persyaratan itu jika tidak, hal itu memengaruhi kegunaan platform. Perhatikan bahwa membiarkan ekspansi parameter tanpa tanda kutip memiliki arti yang sangat khusus sh, bukan sesuatu yang ingin Anda lakukan. Lebih baik untuk menghindari nilai-nilai dummy untuk skrip inline itu $0seperti yang digunakan dalam pesan kesalahan misalnya (seperti saat itu cdakan gagal).
Stéphane Chazelas
Apakah maksud Anda cd "$1"? Jika namanya sulit diketik, mungkin juga mengandung karakter meta shell ...
Toby Speight
benar ini adalah salah ketik
schily