저는 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