일반 파일과 심볼릭 링크 구별

일반 파일과 심볼릭 링크 구별

저는 bash 스크립트를 작성 중인데 일반 파일과 기호 링크를 구별해야 합니다. if/test 표현식을 사용하여 이 작업을 수행할 수 있다고 생각했지만 예상한 대로 작동하지 않습니다.

$ touch regular_file
$ test -f regular_file; echo $?
0
$ test -h regular_file; echo $?
1
$ ln -s regular_file symlink
$ test -h symlink; echo $?
0
$ test -f symlink; echo $?
0

왜 그런 겁니까? 그리고 어떻게 해야 올바르게 할 수 있나요?

답변1

테스트를 약간 망친 것 같습니다. 두 테스트 중 하나를 실행할 필요가 없습니다. 이 경우 필요한 유일한 테스트는 -h파일이 심볼릭 링크인지 여부를 알려주는 테스트입니다.

test -h file && echo "is symlink" || echo "is regular file"

사용 중인 테스트는 -f개체가 파일인지 아니면 파일에 대한 링크인지만 알려줍니다. 1디렉터리, 장치 노드, 디렉터리에 대한 심볼릭 링크 등인 경우에는 (실패)를 반환하지만 0파일에 대한 심볼릭 링크인 경우에는 (성공)을 반환합니다. 즉, 일부 심볼릭 링크는 true로 평가되고 다른 심볼릭 링크는 false로 평가됩니다.

디렉터리가 아닌 파일에 대한 심볼릭 링크인지도 알아야 하는 경우 두 테스트의 결과를 약간의 논리로 결합해야 합니다.

답변2

@Caleb은 스크립트가 심볼릭 링크만 테스트하도록 만드는 것이 옳습니다. 그런데 왜 빠졌는지에 대한 부분이 궁금하네요. coreutils 소스 코드를 보고 테스트 결과를 따라가면 심볼릭 링크 테스트를 실행할 때 lstat를 사용하고, -f로 테스트하면 실제로 심볼릭 링크 뒤에서 "stat"을 호출한다는 것을 알 수 있습니다.

$ ln -s varnish_config XXX
$ strace -s 2000 test -L XXX 2>&1 | grep XXX
execve("/usr/bin/test", ["test", "-L", "XXX"], [/* 47 vars */]) = 0
lstat("XXX", {st_mode=S_IFLNK|0777, st_size=14, ...}) = 0

$ strace -s 2000 test -L varnish_config 2>&1 | grep varnish
execve("/usr/bin/test", ["test", "-L", "varnish_config"], [/* 47 vars */]) = 0
lstat("varnish_config", {st_mode=S_IFREG|0664, st_size=1046, ...}) = 0

$ strace -s 2000 test -f XXX 2>&1 | grep XXX
execve("/usr/bin/test", ["test", "-f", "XXX"], [/* 47 vars */]) = 0
stat("XXX", {st_mode=S_IFREG|0664, st_size=1046, ...}) = 0

통계 매뉴얼 페이지에서:

   stat() stats the file pointed to by path and fills in buf.

   lstat() is identical to stat(), except that if path is a symbolic link,
   then the link itself is stat-ed, not the file that it refers to.

이는 지정된 파일 이름이 일반 파일이거나 일반 파일 자체에 대한 심볼릭 링크일 때마다 -f 테스트가 true를 반환한다는 것을 의미합니다.

답변3

대부분의 test테스트 파일 관련 연산자는 이 작업을 수행합니다.뒤쪽에그렇다면 심볼릭 링크 확인 test -f symlink은 true를 반환합니다.symlink정기적인test -s symlink심볼릭 링크 분석 후 결정된 파일은 비어 있지 않은 파일이나 test -d symlink디렉터리 파일 또는 test -r symlink읽기 가능한 파일 에 대해 동일합니다 .

stat()이를 위해 시스템 호출을 사용합니다 .

유일한 예외는 -L(일반적으로 보다 선호되는 -h) 입니다. 파일이 심볼릭 링크인지 테스트하려면 lstat()궁극적으로 확인되는 파일이 아니라 링크 자체에 대한 정보를 얻기 위해 a를 수행해야 합니다.

그래서 파일이 있는지 확인하려면정기적인문서앞으로기호 링크를 해결하려면 다음이 필요합니다.

if test -f "$file" && test ! -L "$file"; then
  echo is a regular file
fi

심볼릭 링크, 일반 유형, 기타 유형을 명확하게 구분하려면 먼저 다음 test -L작업을 수행해야 합니다.

if test -L "$file"; then
  echo symlink
elif test -f "$file"; then
  echo regular # strictly speaking, it could also have been replaced
               # with a symlink to a regular file since the previous test
else
  echo other type or not accessible
fi

관련 정보