Tidak dapat bergerak ./test ke subdirektori itu sendiri, './test/test'

1

Ketika mencoba mengonversi beberapa file menjadi huruf kecil, saya perhatikan sesuatu yang terasa aneh bagi saya.

Saat menjalankan ini di bash:

find . -iname 'test' | while IFS='\n' read item; do mv $item $(echo $item | tr [:upper:] [:lower:]); done

Dan sumber dan target tidak berubah untuk mv, saya mendapatkan kesalahan berikut:

mv: cannot move '.test' to a subdirectory of itself, './test/test'

Dimana ./test/test berasal dari? Saat gema bukannya mengeksekusi mv, saya mengerti mv ./test ./test. Saya menguji ini pada FreeBSD 10 dan Debian 8.2.0 dengan hasil yang sama. Apa yang saya lewatkan?

Egon Olieux
sumber
Baiklah, masuk akal. Apa yang akan Anda sarankan jika saya ingin mengubah nama banyak direktori? Bisakah ini dilakukan tanpa kesalahan tanpa secara eksplisit memeriksa apakah mereka sama?
Egon Olieux
Saya mengerti mengapa pindah ke pohon yang berbeda akan berhasil, tetapi bagaimana caranya ./* berbeda dari .? ./* akan memperluas ke setiap item dalam direktori sementara . akan mengambil direktori saat ini, tetapi pada akhirnya itu masih bergerak dalam direktori yang sama. Mari ambil direktori dir misalnya yang berisi 5 direktori a, b, c, d dan e. Jika saya ingin mengganti nama semua subdirektori dari dir, find . dan find ./* akan mengembalikan hasil yang sama.
Egon Olieux
Dengan asumsi direktori kerja saat ini adalah dir.
Egon Olieux
@FrankThomas + Egon: -iname test tidak cocok .test; sudah jelas dari hasil kedua (dengan gema) bahwa itu benar-benar ./test dan hanya salah kutip. -ilname persis sama dengan -iname kecuali untuk tautan simbolis yang tidak terlibat di sini. ./* biasanya diperluas ke semua entri di . KECUALI mereka yang memulai . (dot), meskipun beberapa shell memiliki opsi untuk mengubahnya, di bash shopt -s dotglob. OTOH find . akan selalu terlihat seperti dotnames ./.profile (Selain daripada . dan .. ), meskipun di sini nama seperti itu tidak cocok dengan -iname.
dave_thompson_085

Jawaban:

2

Jika nama sudah dalam huruf kecil, itu akan diberikan ke perintah mv dua kali, seperti yang Anda lihat

Jika argumen terakhir ke mv adalah direktori, itu akan diperlakukan sebagai direktori tujuan di mana semua entitas bernama lainnya harus dipindahkan.

mv test test pertama akan memeriksa argumen terakhir, apakah ada dan, jika demikian, apakah itu direktori. Dalam hal ini, maka mv akan memeriksa apakah itu titik mount yang sama (jika tidak, yaitu tujuannya adalah perangkat yang berbeda, perlu menyalin file kemudian menghapus yang asli); dalam hal ini, ya. Jadi mv membangun urutan rename(2) syscalls, menambahkan semua nama sumber pada gilirannya ke direktori yang ditentukan sebagai tujuan: mv a b c d/ akan menghasilkan rename("a", "d/a"), rename("b", "d/b"), dan rename("c", "d/c") - jadi tentu saja mv test test akan mencoba menelepon rename("test", "test/test");. Yang jelas merupakan kesalahan, Anda tidak dapat memindahkan direktori di dalamnya.

Untuk memperbaiki masalah Anda, buat perintah mv tergantung pada nama baru yang berbeda dan belum ada (jika Anda memiliki dua file berbeda yang disebut "Test" dan "test", Anda mungkin tidak ingin mengganti yang kedua tanpa bertanya). Tanpa saya menguji ini, dan mengetiknya di telepon, akan terlihat seperti ini: new="$(echo "$old" | tr ...)"; [[ $new != $old && ! -e $new ]] && mv "$old" "$new" (perhatikan kutipannya, Anda tidak ingin spasi pada nama memberi Anda pengantin metaforis).

Gabe
sumber