UNIX 시스템의 쉘에 로그인하고 명령을 입력하기 시작한다고 가정해 보겠습니다. 처음에는 사용자의 홈 디렉토리로 시작했습니다 ~
. 아마 거기에서 cd
디렉토리로 갈 것입니다 Documents
.
여기서 작업 디렉터리를 변경하는 명령은 이해하기 매우 간단하고 직관적입니다. 상위 노드에는 액세스할 수 있는 하위 노드 목록이 있으며 아마도 검색의 (최적화된) 변형을 사용하여 하위 노드의 존재를 찾습니다. 사용자가 입력한 이름을 입력한 다음 이에 맞게 작업 디렉터리를 "변경"합니다. 제가 틀렸다면 정정해 주세요. 쉘이 사용자가 의도한 대로 정확히 "순진하게" 디렉토리에 액세스하려고 시도하고 파일 시스템이 어떤 유형의 오류를 반환하면 쉘이 이에 따라 응답을 표시하는 것이 더 간단할 수도 있습니다.
그러나 나는 디렉토리 위로 탐색할 때(즉, 상위 디렉토리 또는 상위 디렉토리의 상위 디렉토리로) 동일한 프로세스가 어떻게 작동하는지에 관심이 있습니다.
나의 알려지지 않은, 아마도 "숨겨진" 위치( Documents
전체 파일 시스템 트리에서 해당 이름을 가진 여러 가능한 디렉토리 중 하나)가 주어지면 Unix는 내가 다음에 배치되어야 할 위치를 어떻게 결정합니까?이것을 참조 pwd
하고 확인합니까? 그렇다면 pwd
현재 탐색 상태를 추적하는 방법은 무엇입니까?
답변1
다른 답변은 지나치게 단순화되었으며 각 답변은 이야기의 일부만 제시하며 일부 점에서는 잘못되었습니다.
가지다둘작업 디렉토리를 추적하는 방법:
- 각 프로세스에 대해 커널은 프로세스를 나타내는 커널 공간 데이터 구조의 루트 디렉터리와 프로세스 작업 디렉터리의 vnode에 대한 두 개의 vnode 참조를 저장합니다. 전자에 대한 참조는
chdir()
및 시스템 호출에 의해 설정되고fchdir()
후자는 Linux 운영 체제에서 간접적으로 또는 FreeBSD와 같은 운영 체제의 명령을 통해 볼chroot()
수 있습니다 ./proc
fstat
% fstat -p $$|head -n 5 사용자 명령 PID FD 설치 INUM 모드 SZ|DV R/W JdeBP zsh 92648 text/24958 -r-xr-xr-x 702360 r JdeBP zsh 92648 ctty /dev 148 crw--w---- pts/4 rw JdeBP zsh 92648 wd /usr/home/JdeBP 4 drwxr-xr-x 124 r JdeBP zsh 92648 루트/4 drwxr-xr-x 35r %
경로 이름 확인이 실행되면 경로가 상대 경로인지 절대 경로인지에 따라 참조된 가상 노드 중 하나에서 시작됩니다.
…at()
(세 번째 옵션으로 열린(디렉토리) 파일 설명자가 참조하는 vnode로 경로 이름 확인을 시작할 수 있도록 하는 일련의 시스템 호출이 있습니다 .)마이크로커널 Unices에서 데이터 구조는 애플리케이션 공간에 있지만 이러한 디렉터리에 대한 공개 참조를 유지하는 원칙은 변경되지 않습니다.
- 내부적으로는 Z, Korn, Bourne Again, C, Almquist 쉘 등의 쉘에서또한내부 문자열 변수의 문자열 조작을 사용하여 작업 디렉터리를 추적합니다. 호출할 이유가 있을 때마다 이 작업을 수행합니다
chdir()
.상대 경로 이름으로 변경되면 문자열에 대해 이름을 추가합니다. 절대 경로 이름으로 변경되면 문자열이 새 이름으로 대체됩니다. 두 경우 모두 제거할 문자열
.
과..
구성 요소를 조정하고 기호 링크를 따라가며 링크된 이름으로 바꿉니다. (이것은 Z 쉘의 코드입니다., 예를 들어. )내부 문자열 변수의 이름은 다음과 같습니다.쉘 변수이름
PWD
(또는cwd
C 셸). 일반적으로PWD
쉘 생성 프로그램에 환경 변수(이름 지정)로 내보내집니다.
사물을 추적하는 이 두 가지 방법은 셸에 내장된 명령의 옵션과 셸의 내장 명령 및 명령과 VIM 및 NeoVIM과 같은 내장 기능 간의 차이점을 통해 드러 -P
납니다 -L
.cd
pwd
pwd
/bin/pwd
pwd
% mkdir a ;리소좀 %(cd b; 비밀번호; /bin/pwd; printenv PWD) /usr/홈/JdeBP/b /usr/홈/JdeBP/a /usr/홈/JdeBP/b %(cd b; 비밀번호 -P; /bin/pwd -P) /usr/홈/JdeBP/a /usr/홈/JdeBP/a %(cd b; pwd -L; /bin/pwd -L) /usr/홈/JdeBP/b /usr/홈/JdeBP/b %(cd -P b; 비밀번호; /bin/pwd; printenv PWD) /usr/홈/JdeBP/a /usr/홈/JdeBP/a /usr/홈/JdeBP/a % (cd b; PWD=/hello/거기 /bin/pwd -L) /usr/홈/JdeBP/a %
보시다시피, "논리적" 작업 디렉토리를 얻는 것은 단지 쉘 PWD
변수(또는 쉘 프로그램이 아닌 경우 환경 변수)를 보는 것입니다. "물리적" 작업 디렉토리를 얻는 것은 라이브러리 함수를 호출하는 것입니다 getcwd()
.
/bin/pwd
이 옵션을 사용할 때 프로그램의 작동은 다소 미묘합니다 -L
. 그것믿을 수 없다PWD
상속받는 환경 변수의 값입니다. 결국 이는 쉘에 의해 호출될 필요가 없으며 개입 프로그램은 PWD
작업 디렉토리의 이름을 추적하는 환경 변수를 유지하는 쉘 메커니즘을 구현하지 않을 수 있습니다. 아니면 내가 방금 한 일을 누군가가 할 수도 있습니다.
따라서 이것이 하는 일은 (POSIX 표준에 따르면) 시스템 호출 추적에 표시된 대로 에 제공된 이름이 PWD
name 과 동일한 지 확인하는 것입니다..
낭포내 % % (cd b; truss /bin/pwd -L 3>&1 1>&2 2>&3 | grep -E '^stat|__getcwd') stat("/usr/home/JdeBP/b",{ mode=drwxr-xr-x ,inode=120932,size=2,blksize=131072 }) = 0 (0x0) stat(".",{ 모드=drwxr-xr-x ,inode=120932,size=2,blksize=131072 }) = 0 (0x0) /usr/홈/JdeBP/b % (cd b; PWD=/usr/local/etc truss /bin/pwd -L 3>&1 1>&2 2>&3 | grep -E '^stat|__getcwd') stat("/usr/local/etc",{ mode=drwxr-xr-x ,inode=14835,size=158,blksize=10240 }) = 0 (0x0) stat(".",{ 모드=drwxr-xr-x ,inode=120932,size=2,blksize=131072 }) = 0 (0x0) __getcwd("/usr/home/JdeBP/a",1024) = 0 (0x0) /usr/홈/JdeBP/a % (cd b; PWD=/hello/there truss /bin/pwd -L 3>&1 1>&2 2>&3 | grep -E '^stat|__getcwd') stat("/hello/there",0x7fffffffe730) ERR#2 '해당 파일이나 디렉터리가 없습니다' __getcwd("/usr/home/JdeBP/a",1024) = 0 (0x0) /usr/홈/JdeBP/a % (cd b; PWD=/usr/home/JdeBP/c truss /bin/pwd -L 3>&1 1>&2 2>&3 | grep -E '^stat|__getcwd') stat("/usr/home/JdeBP/c",{ mode=drwxr-xr-x ,inode=120932,size=2,blksize=131072 }) = 0 (0x0) stat(".",{ 모드=drwxr-xr-x ,inode=120932,size=2,blksize=131072 }) = 0 (0x0) /usr/홈/JdeBP/c %
보시다시피 getcwd()
불일치가 감지된 경우에만 호출 되며 PWD
동일한 디렉터리 이름을 다른 경로로 지정하는 문자열을 설정하여 속일 수 있습니다.
라이브러리 getcwd()
기능은 그 자체로 하나의 규율입니다. 그러나 간단히 말하면:
- 원래 이는 디렉토리에서 작업 디렉토리를 반복적으로 찾으려고 시도하여 작업 디렉토리에서 루트 디렉토리로 경로 이름을 구축하는 순전히 라이브러리 함수였습니다
..
. 작업 디렉토리와 동일한 루프 에 도달하거나..
다음 디렉토리를 열려고 시도하는 동안 오류가 발생하면 중지됩니다..
. 이렇게 하면 뒤에서 많은 시스템 호출이 발생합니다. - 이제 상황은 조금 더 복잡해졌습니다. 예를 들어, FreeBSD에서는(다른 운영 체제에서도 마찬가지입니다)예앞서 제공된 시스템 호출 추적에서 볼 수 있듯이 실제 시스템 호출입니다. 작업 디렉터리 vnode에서 루트 디렉터리로의 모든 탐색은 단일 시스템 호출로 수행됩니다. 이는 보다 효율적인 경로 이름 구성 요소 조회를 위해 디렉터리 항목 캐시에 직접 액세스하는 커널 모드 코드와 같은 기능을 활용합니다.
그러나 FreeBSD 및 기타 운영 체제에서도 커널은확실히문자열을 사용하여 작업 디렉터리를 추적합니다.
탐색하는 것은 ..
그 자체로 또 다른 주제입니다. 또 다른 개요: 전통적으로 목차이지만(이미 언급한 것처럼 이것은아니요필수) ..
에는 디스크의 실제 디렉토리 데이터 구조가 포함되어 있으며 커널은 각 디렉토리 vnode 자체의 상위 디렉토리를 추적하여 ..
모든 작업 디렉토리의 vnode로 이동할 수 있습니다. 이는 마운트 지점과 변경된 루트 메커니즘으로 인해 약간 복잡하며 이는 이 답변의 범위를 벗어납니다.
옆에
Windows NT는 실제로 비슷한 작업을 수행합니다. 각 프로세스 SetCurrentDirectory()
에는 API 호출에 의해 설정되고 해당 디렉토리에 대한 (내부) 열린 파일 핸들과 Win32 프로그래밍을 위한 환경 변수 세트를 통해 커널에 의해 추적되는 작업 디렉토리가 있습니다 .모두Win32 프로그램) 여러 작업 디렉터리(각 드라이브당 하나씩)의 이름을 추적하고 디렉터리가 변경될 때마다 해당 디렉터리를 추가하거나 덮어쓰는 데 사용됩니다.
일반적으로 Unix 및 Linux 운영 체제와 달리 Win32 프로그램은 이러한 환경 변수를 사용자에게 표시하지 않습니다. 그러나 때때로 Windows NT에서 실행되는 Unix 계열 하위 시스템이나 SET
특정 방식으로 명령 해석기를 사용하는 명령을 통해 이를 볼 수 있습니다.
추가 읽기
- "
pwd
". 오픈 그룹 기본 사양이슈 7. IEEE 1003.1:2008. 그룹을 엽니다. 2016. - "경로명 확인". 오픈 그룹 기본 사양이슈 7. IEEE 1003.1:2008. 그룹을 엽니다. 2016.
- https://askubuntu.com/a/636001/43344
- 유닉스에서 파일을 여는 방법은 무엇입니까?
- FreeBSD 또는 Solaris에서 inode의 목적은 무엇입니까
- Cygwin!::=::\의 이상한 환경 변수
- 매뉴얼에 설명된 대로 CDPATH가 작동하지 않는 이유는 무엇입니까?
- 물리적 경로를 사용하도록 zsh를 설정하는 방법은 무엇입니까?
- 링크로 연결된 디렉터리를 입력하세요.
답변2
커널은 디렉터리나 파일 이름을 추적하지 않습니다. 파일이나 디렉터리는 inode/장치 쌍으로 커널에 표시됩니다. chdir()
, 기타 시스템 호출은 open()
절대 경로(예: /etc/passwd
) 또는 현재 디렉터리에 대한 상대 경로(예: Documents
, ..
)일 수 있는 매개변수로 경로를 사용합니다. 프로세스가 실행되면 chdir("Documents")
현재 작업 디렉터리에서 조회가 이루어지고 Documents
프로세스의 작업 디렉터리가 해당 디렉터리를 참조하도록 업데이트됩니다. 커널의 관점에서 볼 때 ".."라는 이름에는 특별한 것이 없으며 단지 ..
상위 디렉토리를 참조하기 위한 파일 시스템의 관례일 뿐입니다.
이 getcwd()
함수는 시스템 호출이 아니라 루트 디렉터리까지 실행되고 경로 구성 요소의 이름을 기록해야 하는 라이브러리 함수입니다.
답변3
흥미롭게 도 . cd ..
에 의해 pwd
지정된 디렉토리 는 전통적으로 ..
파일 시스템에 명시적으로 배치됩니다. 시스템은 현재 디렉토리의 장치/인덱스 노드를 추적하므로 cd ..
더 정확하게 시스템 호출은 chdir("..")
현재 디렉토리의 inode에 속하는 파일에서 ".."라는 이름을 찾고 장치/인덱스 노드를 변경하기만 하면 됩니다. 현재 디렉터리의 값을 검색합니다.
pwd
(보다 정확하게는 /bin/pwd
) ..
계속해서 링크를 따라가며 해당 디렉토리의 출처인 inode를 찾을 때까지 해당 디렉토리를 읽고, 루트 디렉토리(특히 항목이 포함되지 않음 ..
)에 도달할 때까지 해당 이름 목록을 역순으로 조립합니다.
이제 이것은 원래의 낮은 수준의 기본 동작입니다. 대신 실제 쉘 명령은 pwd
현재 경로 이름을 캐싱하기 위한 다양한 기술을 사용합니다. 그러나 본질적으로 실제로 알려진 것은 인덱스 노드뿐입니다. 이는 기호 링크를 사용하여 디렉토리를 탐색하면 현재 작업 디렉토리 이름에 대한 현재 쉘과 시스템의 개념이 /bin/pwd
다를 수 있음을 의미합니다.