존재하다이 블로그단일 파일을 가져오는 다음 구조의 bash 스크립트("snippet" 섹션)를 찾았습니다 .bash_profile
.
if [ -d ~/.bash_profile.d ]; then
for file in $( find ~/.bash_profile.d -type f )
do
if [ -f "$file" ]; then
source "$file"
fi
done
fi
find -type f
먼저 bash 연산자를 사용하여 파일을 필터링한 다음 다시 확인하는 것이 합리적입니까 -f
, 아니면 일종의 패치워크입니까?
아래 스크립트도 마찬가지 아닌가요?
if [ -d ~/.bash_profile.d ]; then
for file in $( find ~/.bash_profile.d -type f )
do
source "$file"
done
fi
그렇지 않다면 차이점은 무엇입니까?
답변1
이 코드에는 몇 가지 문제가 있지만 놀랍게도 이중 파일 검사는 그중 하나가 아닙니다.
첫째, @EricRenouf가 보여주듯이 $()
주변 공사가 잘못되었습니다. find
올바른 방법은 다음과 같은 것을 사용하는 것입니다.
while read filename
do
source $filename
done < <(find ....)
서브쉘에서 find를 호출하고 파일 이름을 filename
메인 쉘의 변수로 읽습니다(이것이 find | while read x
아이디어이지만 불행히도 이식 가능하지는 않습니다).
둘째, -d
디렉토리 테스트는 중복됩니다. find
디렉토리가 존재하지 않으면 파일을 찾을 수 없으므로 존재 여부를 테스트할 필요가 없습니다.
그러나 의 매개변수 는 의 매개변수와 정확히 동일한 것을 -type f
테스트하지 않습니다 . find
POSIX에는 다음이 있습니다-f
test
설명하다에 대한 test
:
-에프 경로명
만약에 사실이다경로명일반 파일로 확인되는 기존 디렉터리 항목입니다. 경로 이름을 확인할 수 없거나 경로 이름이 비정규 파일에 대한 기존 디렉터리 항목으로 확인되면 False를 반환합니다.
그리고 이것을 가지고설명하다에 대한 find
:
-유형 씨
파일 유형이 다음과 같은 경우 기본 항목은 true로 평가되어야 합니다.씨, 어디씨블록 특수 파일, 문자 특수 파일, 디렉토리, 심볼릭 링크, FIFO, 일반 파일을 나타내는 'b', 'c', 'd', 'l', 'p', 'f' 또는 's'입니다. 또는 각각 소켓 입니다.
따라서 "파싱할 수 없는" 일반 파일이 있는 경우 test -f
실패하지만 find -type f
성공하는 파일이 있는 것입니다. 이를 달성하는 한 가지 방법은 읽을 수는 있지만 액세스할 수 없는 디렉터리에 파일을 배치하는 것입니다.
wouter@gangtai:~$ ls -ld foo
drw-r--r--. 2 wouter wouter 4096 apr 1 18:38 foo
wouter@gangtai:~$ find foo -type f | while read file; do if [ -f $file ]; then echo $file tests -f; else echo $file does not test -f; fi; done
foo/bar does not test -f
wouter@gangtai:~$ ls -l foo
ls: cannot access 'foo/bar': Permission denied
total 0
-????????? ? ? ? ? ? bar
이것유형파일이 저장된 디렉토리에 대한 권한이 있지만 권한이 없는 경우 r
파일(디렉토리, 일반 파일 또는 기타 파일)에 대한 권한을 감지할 수 있습니다 . x
그러나 이를 "해결"하려면(즉, stat()
해당 파일의 함수 중 하나 호출) x
해당 디렉토리에 대한 권한 비트가 필요합니다.
물론 쉘 스크립트에서 이러한 테스트가 .bashrc
효과가 있는지 여부는 또 다른 문제입니다. 나는 아니오라고 말하고 싶습니다. 그러나 이것이 두 테스트가 동일하다는 의미는 아니며,예이 차이의 상황예중요한...
답변2
for file in ~/.bash_profile.d/*
마침표(.)로 시작하는 파일은 검색되지 않습니다. 극단적인 경우를 포착하려면 조회를 수행하는 것이 좋습니다.
답변3
~/.bash_profile.d/*
모든 하위 디렉터리도 나열되지만 그 안에 있는 파일을 얻기 위해 입력되지는 않습니다.
find
with는 -type f
하위 디렉터리 자체를 제외하고 하위 디렉터리로 이동하여 파일을 가져옵니다. 또한 find
숨겨진 파일도 포함되지만 ~/.bash_profile.d/*
포함되지는 않습니다.
편집하다:
확인 [ -f "$file" ]
이 중복됩니다.
답변4
출력을 처리하고 있으므로 여기서 다시 확인해야 할 수 있습니다. find
이는 출력이 토큰화의 영향을 받는다는 의미입니다. find
인쇄된 이름에 공백이 포함되어 있으면 공백이 파일 이름의 일부일 뿐이므로 $file
실제로 테스트를 통과할 수 없습니다 .-f
예를 들어:
$ touch "~/.bash_profile.d/with space"
$ for f in $( find ~/.bash_profile.d -type f 2>/dev/null );do printf -- "--%s--\n" "$f"; done
--~/.bash_profile.d/with--
--space--
따라서 이 경우 파일을 가리키지 않기 if [ -f "$f" ]
때문에 true를 반환하지 않습니다.$f
이것은 유명한 또 다른 예입니다.ls를 구문 분석하지 마세요질문