Mengapa saya harus keluar dari direktori yang dihapus?

19

Di server saya, saya memiliki struktur direktori yang terlihat seperti ini:

/myproject/code

Saya biasanya memiliki koneksi ssh ke server dan 'berdiri' di direktori itu:

root@machine:/myproject/code#

Ketika saya menggunakan versi baru kode saya, direktori kode dihapus jadi saya pergi dengan:

root@machine:/myproject/code# ./run
-bash: ./run: No such file or directory

Dan satu-satunya solusi yang saya temukan adalah keluar dan masuk kembali:

root@machine:/myproject/code# cd ../code
root@machine:/myproject/code# ./run
Running...

Bisakah saya menghindari ini? Itu perilaku yang agak aneh. Jika Anda memiliki penjelasan yang bagus mengapa ini terjadi, saya akan sangat menghargainya.

Markus Johansson
sumber
5
Pernahkah Anda berpikir untuk menghapus file dalam direktori kode Anda dan bukan direktori kode itu sendiri?
StrongBad
9
Anda salah bahwa direktori yang baru dibuat runsama dengan direktori yang lama. Hanya memiliki nama dan direktori induk yang sama. Bandingkan ini dengan merobek-robek mobil lama Anda dan membeli mobil baru dengan warna dan model yang sama persis: Anda tidak ingin duduk di dalam mobil yang tercabik-cabik dan berharap Anda berakhir dengan yang baru tanpa terluka, bukan?
Anthon
2
Anthon: Yang saya asumsikan adalah path yang mengidentifikasi direktori. Bagi saya "cd ../code" adalah noop. Saya sangat tertarik untuk mendengar mengapa tidak.
Markus Johansson
2
@MarkusJohansson cd ../codebukan noop. ..adalah jalan pintas untuk induk jalur yang Anda miliki, atau dulu Anda miliki. Jika direktori Anda saat ini dihapus, jalur induk mungkin masih ada, dan dalam hal ini dapat dijangkau dengan mengevaluasi ... Dalam direktori itu pencarian dilakukan untuk direktori dengan nama 'kode'.
Anthon
2
@MarkusJohansson Alih-alih menghapus dan kode tarring, saya akan sangat menyarankan untuk menggunakan alat kontrol versi yang tersedia. Jauh lebih mudah untuk membagikan pembaruan (cukup tekan atau tarik) dan sedikit opsi untuk secara tidak sengaja menghapus file yang salah. Dan Anda mempertahankan versi yang lebih lama secara default.
Bernhard

Jawaban:

26

Bagi saya "cd ../code" adalah noop. Saya sangat tertarik untuk mendengar mengapa tidak.

Karena file dan direktori pada dasarnya adalah inode sistem file , bukan nama - ini mungkin detail implementasi yang spesifik untuk tipe sistem file, tetapi itu berlaku untuk semua sistem ext, jadi saya akan tetap menggunakannya di sini.

Ketika direktori barucode dibuat, itu terkait dengan inode baru, dan di situlah tempatnya. Tidak ada catatan tentang file dan direktori yang dihapus sebelumnya, sehingga tidak ada cara yang digunakan sistem untuk memeriksa inode apa yang digunakannya untuk ditempati dan mungkin mengaduk-aduk sekitar sehingga sama lagi; sistem seperti itu akan dengan cepat menjadi tidak bisa dijalankan, dan dalam hal apapun, itu mungkin bukan jaminan bahwa Anda akan kembali ke sana lagi - itu akan menjadi semacam yang tidak diinginkan, karena itu berarti Anda juga bisa secara tidak sengaja berakhir di tempat lain jika direktori dibuat yang mengambil inode Anda (saat ini tidak digunakan).

Saya tidak yakin apakah kemungkinan terakhir ini ada, atau apakah inode dari direktori yang dihapus saat ini ditugaskan untuk direktori kerja Anda saat ini dilacak sehingga tidak ada yang akan ditugaskan untuk itu selama durasi, dll.

goldilocks
sumber
3
Inilah jawaban sebenarnya di sini.
karan.dodia
14

Kulitmu Anda tidak setiap kali melakukan a cdke path yang ada di selama perintah terakhir, sebelum menjalankan perintah berikutnya.

Anda menghapus direktori saat ini dan membuat direktori dengan nama yang sama, yang bukan direktori yang sama, hanya sesuatu dengan nama / jalur yang sama.

Browser file seperti Nautilus dan Windows Explorer biasanya "naik" pohon direktori jika direktori terhapus pada sistem file lokal. Namun ini tidak selalu benar untuk sistem file jaringan, dalam hal ini kadang-kadang penghapusan tidak diperhatikan dan kemunculan kembali bisa membuat Anda berakhir di direktori baru.

Sebuah shell dapat cdmasuk ke direktori saat ini sebelum menjalankan perintah berikutnya, saya tidak mengetahui ada yang melakukan (atau dapat dikonfigurasi untuk melakukannya).

Anthon
sumber
Gamb ilustrasi - secara teori, bahkan mungkin ada sistem file di mana direktori yang lama, dihapus (atau lebih tepatnya tidak terhubung) masih ada dan dapat dibaca, sedangkan yang baru sudah digunakan juga. Itu tidak akan berguna dalam praktek dengan direktori, tetapi dengan file, itu sangat umum.
Volker Siegel
4

Pada kebanyakan sistem mirip UNIX, "direktori saat ini" untuk suatu proses disimpan dalam kernel sebagai deskriptor file yang menunjuk ke direktori itu. Kernel sebenarnya tidak menyimpan path direktori saat ini: informasi tersebut dilacak oleh shell Anda.

Objek filesystem (file atau direktori) hanya dihancurkan untuk selamanya ketika semua tautan filesystem ke sana, dan tidak ada deskriptor file yang menunjuk ke objek tersebut.

Jadi, jika suatu direktori dihapus ketika masih ada proses yang menahannya sebagai direktori kerjanya saat ini, prosesnya cwdakan menjaga direktori tersebut tidak benar-benar dihapus. Tautan filesystem yang menjangkar direktori (entri di direktori induk, dan semua isinya) akan hilang, tetapi direktori itu sendiri akan terus ada sebagai semacam "zombie". Sementara itu, Anda dapat membuat direktori baru di lokasi yang sama dengan yang lama, yang merupakan objek sistem file yang sama sekali berbeda tetapi berbagi jalur yang sama.

Jadi, ketika Anda melakukannya cd ../code(atau, pada banyak shell, cd .), Anda sebenarnya melintasi hierarki sistem file dan pergi ke direktori baru yang berada di alamat lama.

Dengan analogi, menghapus direktori akan seperti memindahkan rumah ke tempat sampah secara paksa (memutuskan hubungan dengan alamat sebelumnya). Jika masih ada seseorang yang tinggal di sana (menggunakannya sebagai milik mereka cwd), mereka harus pergi sebelum rumah itu bisa dihancurkan. Sementara itu, rumah baru dapat dibangun di alamat lama.

nneonneo
sumber
0

@Anthon menjelaskan alasan, mengapa hal itu terjadi
Sebagai solusi, Anda dapat menggunakan alias , sebagai contoh:

alias 1234='PROJECT=`pwd`; cd $PROJECT ; ./run'

alias untuk bash tetap di ~ / .bashrc

MolbOrg
sumber
0

Mengkonfirmasi Direktori kerja saat ini didasarkan pada nomor inode, bukan apa yang Anda cari. Karena Anda menggunakan bash, Anda dapat menggunakan $ PWD sebagai berikut untuk melakukan cd ke direktori baru dengan nama yang sama:

cd $ PWD

Sebagai ilustrasi, saya membuat perintah dummy deploy:

set -x
cd ~/tmp
rm -rf code
mkdir code
echo echo hello from $* > code/run
chmod +x code/run

Membuat penyebaran pertama, cd'd ke kode dan kemudian memeriksa konten ls -laisehingga Anda dapat melihat inode:

ianh@abe:~/tmp$ ./,deploy first
++ cd /home/ianh/tmp
++ rm -rf code
++ mkdir code
++ echo echo hello from first
++ chmod +x code/run
ianh@abe:~/tmp$ cd code
ianh@abe:~/tmp/code$ ls -lai
total 12
22945913 drwxr-xr-x  2 ianh ianh 4096 Apr  9 23:12 .
22937618 drwxrwxr-x 14 ianh ianh 4096 Apr  9 23:12 ..
22939455 -rwxr-xr-x  1 ianh ianh   22 Apr  9 23:12 run

Sekarang jalankan penyebaran ke-2

ianh@abe:~/tmp/code$ ../,deploy 2nd
++ cd /home/ianh/tmp
++ rm -rf code
++ mkdir code
++ echo echo hello from 2nd
++ chmod +x code/run

Dan periksa isi direktori ... sekarang tidak ada apa pun di direktori! bahkan tidak '.' dan '..'! Dari sini Anda dapat melihat bahwa bash tidak menggunakan entri direktori '..' ketika Anda menjalankan cd ..sejak '..' tidak ada lagi - saya kira itu bagian dari penanganan $ PWD-nya. Beberapa shell lain / lama tidak menangani cd ..dalam situasi ini, Anda harus cd ke jalur absolut terlebih dahulu.

ianh@abe:~/tmp/code$ ls -lai
total 0

Cd ke $PWDdan coba lagi:

ianh@abe:~/tmp/code$ cd $PWD
ianh@abe:~/tmp/code$ ls -lai
total 12
22945914 drwxr-xr-x  2 ianh ianh 4096 Apr  9 23:12 .
22937618 drwxrwxr-x 14 ianh ianh 4096 Apr  9 23:12 ..
22939455 -rwxr-xr-x  1 ianh ianh   20 Apr  9 23:12 run
ianh@abe:~/tmp/code$ ./run
hello from 2nd

Perhatikan bagaimana inode untuk direktori saat ini (.) Berubah?

Jika skrip deploy Anda memindahkan direktori lama ke nama lain, misalnya mv code code.$$dalam skrip, deploy skrip di atas, maka ./runakan berfungsi, tetapi sampai Anda menggunakan cd $PWDAnda akan menjalankan kode lama , bukan yang baru.

ianh@abe:~/tmp/code$ ./run
hello from 2nd
ianh@abe:~/tmp/code$ ../,deploy 3rd
++ cd /home/ianh/tmp
++ '[' -d code ']'
++ mv code code.9629
++ mkdir code
++ echo echo hello from 3rd
++ chmod +x code/run
ianh@abe:~/tmp/code$ ./run
hello from 2nd
ianh@abe:~/tmp/code$ cd $PWD
ianh@abe:~/tmp/code$ ./run
hello from 3rd

Menyebarkan menggunakan capistrano memiliki masalah yang sama (Mereka memiliki symlink dari nama saat ini ke rilis saat ini), jadi saya menggunakan alias untuk cd ke area produksi / pementasan serta mengatur RAIL_ENV tepat:

alias cdp='export RAILS_ENV=production; echo RAILS_ENV=$RAILS_ENV ; cd /var/www/www.example.com/current'
alias cds='export RAILS_ENV=staging; echo RAILS_ENV=$RAILS_ENV ; cd /var/www/staging.example.com/current'
iheggie
sumber
0

Apa yang saya asumsikan adalah bahwa path adalah apa yang mengidentifikasi direktori.

Jalan menuju sesuatu adalah bagaimana Anda sampai di sana, bukan hal itu sendiri. Jalan menuju tempat tidur Anda mungkin melalui kamar Anda, tetapi begitu Anda berada di tempat tidur, jika seseorang mengambilnya dan membawanya keluar, Anda tidak lagi berada di kamar Anda.

psusi
sumber
0

Bukan jawaban yang lengkap, tetapi saya memiliki poin tambahan, yang margin komentarnya terlalu kecil untuk dikandung.

Untuk lebih memahami gagasan bahwa direktori dalam sistem file yang relevan lebih dari sekadar path, coba pindahkan direktori kerja proses lain saat ini: dalam satu shell, mulailah sesi Python interaktif:

$ python
>> import os
>> os.getcwd()
'/home/you/hocus'

Lalu, buka shell lain dan pindahkan direktori itu:

$ cd /home/you
$ mv hocus pocus

Kembali ke yang asli:

$ python
>> impor os
>> os.getcwd ()
'/ home / you / hocus'
>> os.getcwd ()
'/ home / you / pocus'
Evgeni Sergeev
sumber