"-f" bash 연산자를 사용하여 "find -type -f" 결과를 다시 확인해야 할 이유가 있나요?

"-f" bash 연산자를 사용하여 "find -type -f" 결과를 다시 확인해야 할 이유가 있나요?

존재하다이 블로그단일 파일을 가져오는 다음 구조의 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테스트하지 않습니다 . findPOSIX에는 다음이 있습니다-ftest설명하다에 대한 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/*모든 하위 디렉터리도 나열되지만 그 안에 있는 파일을 얻기 위해 입력되지는 않습니다.
findwith는 -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를 구문 분석하지 마세요질문

관련 정보