Почему я должен cd из удаленного каталога?

19

На моем сервере структура каталогов выглядит примерно так:

/myproject/code

У меня обычно есть SSH-соединение с сервером и «стоять» в этом каталоге:

root@machine:/myproject/code#

Когда я развертываю новую версию своего кода, каталог кода удаляется, поэтому у меня остается:

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

И единственное решение, которое я нашел, это переписаться и вернуться:

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

Могу ли я избежать этого? Это несколько странное поведение. Если у вас есть хорошее объяснение, почему это происходит, я был бы признателен.

Маркус Йоханссон
источник
5
Задумывались ли вы об удалении файлов в каталоге кода, а не в самом каталоге кода?
StrongBad
9
Вы ошибаетесь, что вновь созданный каталог runсовпадает со старым каталогом. Он имеет только то же имя и родительский каталог. Сравните это с тем, что вы измельчаете свою старую машину и покупаете новую машину точно такого же цвета и модели: вы не хотели бы сидеть в машине, которую разрывают, и надеетесь, что вы окажетесь на новой целой, не так ли?
Anthon
2
Anthon: я предполагаю, что путь - это то, что определяет каталог. Для меня "cd ../code" - это пустяк. Мне очень интересно услышать, почему это не так.
Маркус Йоханссон
2
@MarkusJohansson cd ../code- это не шумиха. ..является ярлыком для родительского пути, который у вас есть или использовался. Если ваш текущий каталог удален, родительский путь все еще может существовать, и в этом случае он будет доступен для оценки ... В этом каталоге выполняется поиск каталога с именем «код».
Anthon
2
@MarkusJohansson Вместо удаления и хранения кода я настоятельно рекомендую использовать любой доступный инструмент контроля версий. Гораздо проще поделиться обновлениями (просто нажать или потянуть) и меньше возможностей для случайного удаления неправильных файлов. И вы сохраняете старую версию по умолчанию.
Бернхард

Ответы:

26

Для меня "cd ../code" - это пустяк. Мне очень интересно услышать, почему это не так.

Поскольку файлы и каталоги являются в основном инодами файловой системы , а не именами - возможно, это детали реализации, специфичные для типа файловой системы, но это верно для всех систем ext, поэтому я буду придерживаться этого здесь.

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

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

лютик золотистый
источник
3
Это реальный ответ здесь.
karan.dodia
14

Ваша оболочка не каждый раз указывает cdпуть, по которому она была во время последней команды, перед выполнением следующей команды.

Вы удалили текущий каталог и создали каталог с тем же именем, который не является тем же каталогом, просто что-то с тем же именем / путем.

Файловые браузеры, такие как Nautilus и Windows Explorer, обычно «поднимаются» по дереву каталогов, если каталог удаляется в локальной файловой системе. Однако это не всегда верно для сетевых файловых систем, в этом случае иногда удаление не замечается, и повторное появление может привести к тому, что вы окажетесь в новом каталоге.

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

Энтон
источник
Фоль иллюстрация - теоретически, может даже существовать файловая система, в которой старый, удаленный (или, скорее, несвязанный) каталог все еще существует и доступен для чтения, в то время как новый уже используется. Это не было бы полезно на практике с каталогами, но с файлами, это довольно часто.
Фолькер Сигел
4

В большинстве UNIX-подобных систем «текущий каталог» процесса хранится в ядре как дескриптор файла, указывающий на этот каталог. Ядро фактически не хранит путь к текущему каталогу: эта информация отслеживается вашей оболочкой.

Объект файловой системы (файл или каталог) уничтожается навсегда, только когда все ссылки на него отсутствуют, а файловые дескрипторы не указывают на этот объект.

Таким образом, если каталог удален, пока существует процесс, который удерживает его в качестве текущего рабочего каталога, процесс не cwdпозволит каталогу быть действительно удаленным. Ссылки на файловую систему, которые привязывают каталог (его запись в родительском каталоге и все его содержимое), будут удалены, но сам каталог будет продолжать существовать как своего рода «зомби». Между тем, вы можете создать новый каталог в том же месте, что и старый, который является совершенно другим объектом файловой системы, но имеет тот же путь.

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

По аналогии, удаление каталога было бы похоже на принудительное перемещение дома на свалку (разрыв связи с предыдущим адресом). Если бы там еще кто-то жил (используя его как свою cwd), им пришлось бы уйти до того, как дом мог быть разрушен. Тем временем, новый дом может быть построен по старому адресу.

nneonneo
источник
0

@Anthon прояснил причины, почему это происходит.
В качестве решения вы можете использовать псевдоним , например:

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

псевдонимы для bash хранятся в ~ / .bashrc

MolbOrg
источник
0

Подтверждение Текущий рабочий каталог основан на номере инода, а не на том, что вы искали, чтобы попасть туда. Поскольку вы используете 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чтобы вы могли видеть 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

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

Перейдите $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

Обратите внимание, как изменился индекс для текущего каталога (.)?

Если ваш сценарий развертывания перенес старый каталог на другое имя, например, 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 имеет ту же проблему (у них есть символическая ссылка от имени текущего к текущему выпуску), поэтому я использую псевдонимы для cd в производственных / промежуточных областях, а также соответственно устанавливаю 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'
iheggie
источник
0

Я предполагаю, что путь - это то, что определяет каталог.

Путь к чему-то - это то, как вы туда попадаете, а не сама вещь. Путь к вашей кровати может проходить через вашу комнату, но как только вы окажетесь в постели, если кто-то поднимет ее и вынесет на улицу, вас больше не будет в вашей комнате.

psusi
источник
0

Не самодостаточный ответ, но у меня есть дополнительный момент, который поле для комментариев было слишком маленьким, чтобы его содержать.

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

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

Затем перейдите в другую оболочку и переместите этот каталог:

$ cd /home/you
$ mv hocus pocus

Вернуться к оригиналу:

$ python
>> импорт ОС
>> os.getcwd ()
«/ Дом / вы / опаивать»
>> os.getcwd ()
«/ Дом / вы / покус»
Евгений Сергеев
источник