find .
이들명령으로 입력하는 것의 /home/user/*
차이점은 무엇인가요 for
? 예를 들어:
for var in $(find .)
do echo "$var"
done
또는
for var in /home/user/*
do
echo "$var"
done
첫 번째 경우, for
명령은 이름에 공백이 포함된 파일을 폭발시킵니다. 두 번째 경우에는 그렇지 않습니다. 왜?
답변1
이는 쉘의 표준 동작입니다. 작업 순서는 명령 대체( $(find .)
), 단어 분할, 전역 확장( /home/user/*
)입니다.
~에서POSIX 표준(단어 분할 = 필드 분할, 전역 확장 = 경로명 확장):
단어 확장 순서는 다음과 같습니다.
물결표 확장(물결표 확장 참조), 매개변수 확장(매개변수 확장 참조), 명령 대체(명령 대체 참조) 및 산술 확장(산술 확장 참조)은 처음부터 끝까지 수행되어야 합니다. 토큰 인식의 항목 5를 참조하세요.
IFS가 비어 있지 않으면 1단계에서 생성된 필드 부분에 대해 필드 분할을 수행해야 합니다(필드 분할 참조).
set -f가 적용되지 않는 한, 경로 이름 확장이 수행되어야 합니다(경로 이름 확장 참조).
견적 삭제(견적 삭제 참조)는 항상 마지막에 수행되어야 합니다.
따라서 단어 분할이 파일 이름을 방해하지 않도록 가능하면 항상 glob을 사용하는 것이 좋습니다. 구성 $(find)
은 실제로 예입니다.배쉬 트랩 #1.
답변2
쉘은 순차적으로 작업을 수행합니다. $(find .)
이를 명령 대체라고 합니다. 명령 대체 결과는 다음의 영향을 받습니다.
- 분사,
- 경로명 확장
- 견적 삭제
단어 분리는 파일 이름에 공백이 있을 때 문제를 일으키는 원인입니다.
/home/user/*
경로 이름 확장자입니다. 이는 위 목록에서 마지막에서 두 번째 항목입니다. 견적 삭제에만 영향을 받습니다.
답변3
둘 사이의 또 다른 차이점은 쉘 glob(예: globs /home/user/*
)에는 일반적으로 "숨겨진 파일"(점으로 시작하는 파일 이름)이 포함되어 있지 않다는 것입니다. 반면, find
특수 디렉토리 "."를 제외한 모든 파일 이름은 일치됩니다. 및 ".."(현재 디렉터리 및 상위 디렉터리).
답변4
이를 설명하는 또 다른 방법은 *
사용 시 쉘이 개별 요소가 무엇인지 알 수 있다는 것입니다. 출력은 find
단지 긴 문자열입니다. 쉘은 요소(및 해당 구분 기호)가 무엇인지 전혀 모릅니다.
인용된 출력을 생성하는 프로그램에서 명령 대체를 특별한 방식으로 사용할 수 있으면 문제가 발생하지 않습니다. 그러나 예를 들어 쉘이 필요한 따옴표를 인식하려면 eval
전체 표현식이 더 복잡해지는 경우가 많습니다.
eval for var in $(ls --quoting-style=shell)\; do echo '"$var"'\; done