일반 파일을 심볼릭 링크와 구별 해야하는 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
왜 그런가요? 그리고 어떻게 제대로 할 수 있습니까?
답변
테스트를 약간 혼란스럽게하는 것처럼 보입니다. 두 가지 테스트를 모두 실행할 필요는 없습니다.이 경우에 필요한 유일한 -h
것은 파일이 심볼릭 링크인지를 알려주는 것입니다.
test -h file && echo "is symlink" || echo "is regular file"
-f
객체가 파일 인 경우 테스트는 당신을 알려줍니다. 이 반환 0
은 디렉토리 또는 디바이스 노드 또는 디렉토리에 대한 심볼릭 링크가 있다면,하지만 돌아갑니다 1
파일로 심볼릭 링크에.
디렉토리가 아닌 파일에 대한 심볼릭 링크인지 알아야하는 경우 두 테스트 결과를 약간의 논리와 결합해야합니다.
답변
@Caleb은 스크립트를 심볼릭 링크로 테스트하는 것에 대해 정확합니다. 그러나 왜 빠졌는지에 대한 부분은 궁금했습니다. coreutils 소스 코드를보고 테스트 결과를 추적하면 심볼릭 링크 테스트를 실행할 때 lstat를 사용하고 -f 테스트를 사용하는 경우 실제로 symlink 다음에 ‘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를 반환 함을 의미합니다.