Чому я повинен вийти з видаленого каталогу?


19

На моєму сервері я маю структуру каталогу, яка виглядає приблизно так:

/myproject/code

У мене зазвичай є ssh-з'єднання із сервером і 'stand' у цьому каталозі:

root@machine:/myproject/code#

Коли я розгортаю нову версію свого коду, каталог коду видаляється, тому мені залишається:

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

І єдине знайдене нами рішення - це вивести CD і повернутись назад:

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

Чи можу я цього уникнути? Це дещо дивна поведінка. Якщо у вас є гарне пояснення, чому це відбувається, я би вдячний.


5
Чи думали ви про видалення файлів у каталозі коду, а не в самій кодовій директорії?
StrongBad

9
Ви помиляєтесь, що новостворений каталог runтакий же, як і старий каталог. Він має лише те саме ім’я та батьківський каталог. Порівняйте це з вашим подрібненням старого автомобіля та придбанням нового автомобіля точно такого ж кольору та моделі: Ви б не хотіли сидіти в машині, що перетирається, і сподіваєтесь, що ви натрапите на нову, неушкоджену, чи не так?
Антон

2
Ентон: Я припускаю, що шлях - це те, що ідентифікує каталог. Для мене "cd ../code" - noop. Мені дуже цікаво почути, чому це не так.
Маркус Йоханссон

2
@MarkusJohansson cd ../code- не нуп. ..- це ярлик для батьків із шляху, який у вас є чи у вас раніше. Якщо ваш поточний каталог видалено, батьківський шлях може все ще існувати, і в цьому випадку можна отримати його шляхом оцінки ... У цьому каталозі здійснюється пошук каталогу з назвою 'code'.
Антон

2
@MarkusJohansson Замість того, щоб видаляти та призначати код, я настійно рекомендую використовувати будь-який доступний інструмент контролю версій. Набагато простіше ділитися оновленням (просто натиснути або потягнути) та менше варіантів випадкового видалення неправильних файлів. І ви зберігаєте стару версію за замовчуванням.
Бернхард

Відповіді:


26

Для мене "cd ../code" - noop. Мені дуже цікаво почути, чому це не так.

Оскільки файли та каталоги в основному є входами файлової системи , а не іменами - це, можливо, деталі реалізації, характерні для типу файлової системи, але це правда для всіх систем ext, тому я дотримуюся цього тут.

Коли створюється новий каталог code, він асоціюється з новим inode, і саме там він знаходиться. Не зберігається жодного запису раніше видалених файлів і каталогів, тому немає засобів, за допомогою яких система могла б перевірити, який саме вузол займає, і, можливо, перетасувати речі навколо, щоб він знову був таким же; така система швидко стала б непрацездатною, і, у будь-якому випадку, це, мабуть, не гарантія того, що ти знову опинишся там - це було б небажано, оскільки це означає, що ти також можеш випадково опинитися десь в іншому місці, якщо буде створений каталог який бере ваш (наразі невикористаний) inode.

Я не впевнений, чи існує ця остання можливість, чи відслідковується вкладення видаленого каталогу, присвоєного вашому поточному робочому каталогу, так що нічого не буде призначено йому протягом тривалості тощо.


3
Це справжня відповідь тут.
karan.dodia

14

Ваша оболонка не кожен раз виконує cdшлях до того шляху, яким він був під час останньої команди, перш ніж виконувати наступну команду.

Ви видалили поточний каталог і створили каталог з тим самим іменем, який не є тим самим каталогом, просто щось з тим самим іменем / шляхом.

Файлові браузери, такі як Nautilus та Windows Explorer, зазвичай "піднімають" дерево каталогів, якщо каталог видаляється в локальній файловій системі. Однак це не завжди справедливо для мережевих файлових систем; у такому випадку іноді видалення не помічається, і повторне поява може призвести до того, що ви потрапите в новий каталог.

Оболонка могла cdпотрапити в поточний каталог перед виконанням наступної команди, я не знаю, що робити (або може бути налаштовано для цього).


Наочна ілюстрація - теоретично може існувати навіть файлова система, де стара, видалена (а точніше незв'язана) директорія все ще існує та читається, а нова вже використовується. Це не було б корисно на практиці з каталогами, але з файлами, це досить часто.
Volker Siegel

4

У більшості UNIX-подібних систем "поточний каталог" процесу зберігається в ядрі як дескриптор файлу, що вказує на цей каталог. Ядро насправді не зберігає шлях поточного каталогу: ця інформація відстежується вашою оболонкою.

Об'єкт файлової системи (файл чи каталог) знищується назавжди лише тоді, коли всі посилання файлової системи на нього відсутні, і дескриптори файлів не вказують на цей об’єкт.

Отже, якщо каталог буде видалено, поки процес все ще зберігається як його поточний робочий каталог, цей процес cwdдозволить уникнути справді видалення каталогу. Посилання на файлову систему, які закріплюють каталог (його запис у батьківському каталозі та весь його вміст) не буде, але сам каталог буде продовжувати існувати як свого роду "зомбі". Тим часом ви можете створити абсолютно новий каталог у тому самому місці, що і старий, який є абсолютно іншим об’єктом файлової системи, але який має той самий шлях.

Таким чином, коли ви робите cd ../code(або на багатьох оболонках cd .), ви фактично переходите до ієрархії файлової системи та переходите до нового каталогу, який знаходиться за старою адресою.

За аналогією, видалення каталогу було б як насильницьке переміщення будинку на смітник (розрив зв'язків із попередньою адресою). Якби там ще хтось жив (використовуючи це як своє cwd), їм довелося б виїхати, перш ніж будинок можна було зруйнувати. А поки що за старою адресою можна було б збудувати абсолютно новий будинок.


0

@Anthon усунув причини, чому це відбувається
як рішення Ви можете використовувати псевдонім , наприклад:

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

псевдоніми для bash зберігаються в ~ / .bashrc


0

Підтвердження поточного робочого каталогу IS на основі номера inode, а не того, що ви шукали, щоб потрапити туди. Оскільки ви використовуєте bash, ви можете використовувати $ PWD наступним чином, щоб перейти до нового однойменного каталогу:

cd $ PWD

Для ілюстрації я зробив команду фіктивного розгортання:

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

Створив перший розгортання, cd'd кодувати, а потім перевіряв вміст, ls -laiщоб ви могли бачити вставки:

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

Тепер запустіть 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

І перевірте вміст каталогу ... тепер у каталозі нічого немає! навіть не '.' і '..'! З цього видно, що bash не використовує запис каталогу "..", коли ви запускаєте, cd ..оскільки ".." більше не існує - я припускаю, що є його частиною $ PWD-обробкою. Деякі інші / старіші оболонки не справляються cd ..в цій ситуації, вам потрібно спершу перейти на абсолютний шлях.

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

Cd до $PWDта спробуйте ще раз:

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

Зверніть увагу, як змінився inode для поточного каталогу (.)?

Якщо розгорнути сценарій переміщений старий каталог з яким - або іншим ім'ям, наприклад , mv code code.$$в, розгорнути сценарій вище, то ./runбуде працювати, але поки ви не використовуєте cd $PWDви б запустити старий код, а не нова.

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

Розгортання за допомогою capistrano має таку ж проблему (у них є посилання від поточного імені до поточного випуску), тому я використовую псевдоніми для переходу на області виробництва / постановки, а також встановити RAIL_ENV відповідним чином:

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'

0

Я припускаю, що шлях - це те, що ідентифікує каталог.

Шлях до чогось - це те, як ти туди потрапиш, а не сама річ. Шлях до вашої ліжка може проходити через вашу кімнату, але як тільки ви перебуваєте в ліжку, якщо хтось забирає його і виносить його на вулицю, ви вже не в своїй кімнаті.


0

Це не є самодостатньою відповіддю, але у мене є додатковий пункт, котрий розміщення коментарів було занадто малим.

Щоб краще відчути думку про те, що каталог у відповідних файлових системах - це не просто шлях, спробуйте перенести поточний робочий каталог іншого процесу: в одній оболонці запустіть інтерактивний сеанс Python:

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

Потім перейдіть до іншої оболонки та перемістіть цей каталог:

$ cd /home/you
$ mv hocus pocus

Повернутися до оригіналу:

$ пітон
>> імпортувати ос
>> os.getcwd ()
'/ додому / ти / хокус'
>> os.getcwd ()
'/ home / you / pocus'
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.