삭제된 디렉터리에서 종료해야 하는 이유는 무엇입니까?

삭제된 디렉터리에서 종료해야 하는 이유는 무엇입니까?

내 서버에는 다음과 같은 디렉토리 구조가 있습니다.

/myproject/code

나는 일반적으로 서버에 SSH로 연결하고 해당 디렉토리에 "대기"합니다.

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...

이것을 피할 수 있나요? 이것은 조금 이상한 행동입니다. 왜 이런 일이 발생하는지에 대해 좋은 설명이 있으면 매우 감사하겠습니다.

답변1

나에게 "cd ../code"는 바보입니다. 왜 이것이 사실이 아닌지 듣고 싶습니다.

파일과 디렉토리는 본질적으로파일 시스템 아이노드, 이름보다는 - 이것은 파일 시스템 유형에 특정한 구현 세부 사항일 수 있지만 모든 외부 시스템에 해당되므로 여기서는 계속 사용하겠습니다.

언제새로운디렉토리가 code생성된 후에는 해당 디렉토리가 있는 새 inode와 연결됩니다. 이전에 삭제된 파일 및 디렉터리에 대한 기록은 보관되지 않으므로 시스템은 한 번 점유된 inode를 검사할 수 없으며 내용을 다시 동일하게 만들기 위해 재배열할 수도 없습니다. 이러한 시스템은 빠르게 작동하지 않게 되며 어떤 경우에도 다시 그곳으로 돌아갈 것이라는 보장은 없습니다. 이는 다소 바람직하지 않습니다. 이는 디렉토리가 생성되면 실수로 (현재 사용되지 않는) inode가 필요한 다른 위치로 끝날 수도 있음을 의미하기 때문입니다.

이 마지막 가능성이 존재하는지 또는 현재 작업 디렉토리에 현재 할당된 삭제된 디렉토리의 inode가 추적되어 해당 기간 동안 아무것도 할당되지 않는지 확실하지 않습니다.

답변2

너의 껍질아니요다음 명령을 실행하기 전에 매번 cd이전 명령이 실행된 경로에서 작업이 수행됩니다.

현재 디렉터리를 삭제하고 동일한 이름의 디렉터리를 생성했는데, 이는 동일한 디렉터리가 아니고 동일한 이름/경로를 가진 디렉터리일 뿐입니다.

로컬 파일 시스템의 디렉터리가 삭제되면 Nautilus 및 Windows 탐색기와 같은 파일 브라우저는 종종 디렉터리 트리를 "위"로 이동합니다. 그러나 네트워크 파일 시스템의 경우 항상 그런 것은 아닙니다. 이 경우 때로는 삭제가 눈에 띄지 않고 다시 나타나서 새 디렉토리에 남게 될 수도 있습니다.

셸은 cd다음 명령을 실행하기 전에 현재 디렉터리로 이동할 수 있지만, 이 작업을 수행하는 항목은 없습니다(또는 이를 수행하도록 구성할 수 있음).

답변3

대부분의 UNIX 계열 시스템에서 프로세스의 "현재 디렉터리"는 해당 디렉터리를 가리키는 파일 설명자로 커널에 저장됩니다. 커널은 실제로 현재 디렉토리에 대한 경로를 저장하지 않습니다. 이 정보는 쉘에 의해 추적됩니다.

파일 시스템 객체(파일또는디렉토리)은 모든 파일 시스템 링크가 사라진 경우에만 영구적으로 파괴됩니다.그리고객체를 가리키는 파일 설명자가 없습니다.

따라서 디렉터리를 삭제했는데 해당 디렉터리를 현재 작업 디렉터리로 유지하는 프로세스가 여전히 있는 경우 해당 프로세스는 cwd디렉터리가 실제로 삭제되는 것을 방지합니다. 디렉터리(상위 디렉터리의 항목과 모든 내용)를 고정하는 파일 시스템 링크는 사라지지만 디렉터리 자체는 일종의 "좀비"로 계속 존재합니다. 동시에 이전 디렉터리와 동일한 위치에 완전히 새로운 디렉터리를 생성할 수 있습니다. 이는 완전히 다른 파일 시스템 개체이지만 동일한 경로를 공유합니다.

따라서 이 작업을 수행하면 cd ../code(또는 많은 쉘에서 cd .) 실제로 파일 시스템 계층 구조를 탐색하고새로운이전 주소의 디렉토리입니다.

비유하자면, 디렉토리를 삭제하는 것은 집을 강제로 쓰레기장으로 옮기는 것과 같습니다(이전 주소와의 연결 끊기). 아직도 그곳에 살고 있는 사람이 있다면(자신의 집으로 사용하는 경우 cwd) 집이 철거되기 전에 떠나야 합니다. 그동안 이전 주소에 완전히 새로운 집을 지을 수 있습니다.

답변4

현재 작업 디렉토리가 조회한 디렉토리 번호가 아닌 inode 번호를 기반으로 하는지 확인하십시오. bash를 사용하고 있으므로 $PWD를 사용하여 동일한 이름의 새 디렉터리로 이동할 수 있습니다.

CD $PWD

이를 설명하기 위해 더미 배포 명령을 만들었습니다.

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

첫 번째 배포를 생성하고 코드로 이동한 후 ls -laiinode를 볼 수 있도록 내용을 검사합니다.

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

이제 두 번째 배포를 실행하세요.

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 ..이 상황을 처리할 수 없으므로 먼저 절대 경로로 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'

관련 정보