*.e*
다른 파일( )과 같은 디렉토리에 있는 파일( )을 찾으려고 합니다 md.tpr
. 추가 처리를 위해 다음을 사용하여 해당 항목을 나열해야 합니다.
find . -name md.tpr -execdir ls *.e* \;
나는 이 명령의 몇 가지 변형과 다른 몇 가지 변형을 시도했습니다(명령에 작은따옴표 전달 또는 몇 가지 이름을 지정하기 위해 전달 -execdir
하는 것을 포함). 와일드카드는 또는 에 전달될 때 작동하지 않는 것 같습니다 . 위 명령을 실행할 때 발생하는 오류는 다음과 같습니다.sh -c 'ls *.e*'
eval 'ls *.e*'
-exec
-execdir
ls: *.e*: No such file or directory
온전성 검사와 마찬가지로 인쇄해야 할 내용이 인쇄되었으므로 해당 테스트에서 나열된 디렉터리에 파일이 존재하므로 -execdir pwd
와일드카드 문제인 것처럼 보입니다 .*.e*
이제 덜 우아한 방식으로 이 문제를 해결할 수 있었지만 여기서는 왜 와일드카드와 와일드카드가 작동하지 않는지 혼란스러울 뿐입니다. 어떤 아이디어가 있나요? 아니면 내가 완전히 궤도를 벗어난 걸까?
저는 bash 3.2.25(이전 버전이지만 해당 시스템에 대한 관리자 권한이 없음)를 사용하고 있습니다.
또한 흥미롭게도 내가 그렇게 한다면
find ~ -name .bashrc -maxdepth 2 -execdir ls -d .b* \;
에서 완료하지 않으면 작동하지 않습니다 $HOME
.
답변1
find 명령과 쉘 모두 가능파일 글로빙.
이는 특이한 현상입니다. 대부분의 명령은 와일드카드를 사용할 수 없으며 와일드카드를 확장하기 위해 전적으로 쉘에 의존합니다. 하지만 find는 슈퍼 슈퍼 슈퍼 사용자 도구이고 이로 인해 쉽게 다칠 수 있습니다!
예: 명령을 실행할 때
find /path -iname *.txt
가장 먼저 일어나는 일은 쉘이 현재 디렉토리에서 *.txt와 일치하는 모든 파일을 찾으려고 시도한다는 것입니다. 발견되면 다음 이름으로 대체됩니다.모두glob을 찾은 다음 find 명령을 호출하십시오. 찾기 명령결코 큰 그림을 보지 마라이런 일이 발생하면 쉘은 이를 존재하지 않는 것으로 확장했습니다.
그러나 현재 디렉토리에 glob과 일치하는 파일이 없으면 쉘은 어깨를 으쓱하고 다음변경되지 않은 글로브 전달찾다. 따라서 이 시점에서 find 명령(glob을 이해한다는 점을 기억하세요)은 glob과 일치하는 /path에서 찾은 모든 파일의 이름을 인쇄합니다.
따라서 이러한 방식으로 glob을 사용한다는 것은 find가 현재 디렉터리의 내용에 따라 다르게 동작한다는 것을 의미합니다. 이것은 거의 확실히 당신이 원하는 것이 아닙니다!
find가 글로브를 보기 전에 쉘이 글로브를 조작하는 것을 방지하려면,glob을 이스케이프하려면 적절한 쉘 메타 문자 인용을 사용하십시오. 일반적으로 이는 글로브스트링을 다음과 같이 작은따옴표로 묶는 것을 의미합니다.
find /path -iname '*.txt'
GLOBS는 정규 표현식이 아니라는 점을 기억하십시오. glob ".*"와 정규 표현식 ".*"은 매우 다르며 동일한 문자열과 일치하지 않습니다!
답변2
.b*
따옴표가 없는 전역 변수(예: 또는 )가 포함된 명령을 입력하면 *.e*
셸이 해당 명령을 확장합니다. 나는 전에 이런 일이 일어나는 것을 본 적이 있습니다 find
.
디렉토리에 등의 파일이 있을 수 있습니다 .bashrc
. 따라서 다른 곳에서 실행하면 명령은 가 됩니다. 다른 곳에서 실행하면 해당 glob은 어떤 것과도 일치하지 않으므로 전달됩니다. 전 세계적으로 아무 것도 수행하지 않으므로 여전히 작동하지 않습니다. glob을 확장하려면 셸을 호출해야 합니다..bash_history
$HOME
$HOME
find ... -execdir ls -d .bashrc .bash_history ... \;
.b*
find -exec
*
-exec
find ... -execdir sh -c 'echo globs: *' \;
답변3
bash
쉘이 주어진 와일드카드 패턴과 일치하는 파일을 찾을 수 없으면 패턴을 확장되지 않은 상태로 둡니다 . 이로 인해 find
명령이 ls
확장되지 않은 패턴을 *.e*
인수로 갖게 됩니다. 유틸리티 ls
자체는 파일 이름 와일드카드 패턴을 확장하지 않지만 이를 수행하려면 셸을 사용합니다.
이는 홈 디렉토리에서만 제대로 작동하는 것처럼 보이는 마지막 명령의 문제일 가능성이 높습니다. find
홈 디렉토리에 패턴과 일치하는 파일( .bashrc
예: match .b*
)이 포함되어 있기 때문일 수 있습니다. 패턴이 현재 디렉터리의 어떤 것과도 일치하지 않으면 패턴은 ls
그대로 전달되며, ls
와일드카드 패턴 자체는 확장되지 않으므로 어떤 파일도 나열할 수 없습니다.
즉, ls
직접 -execdir
또는 호출을 사용하여 -exec
파일 이름 글로빙 패턴을 제공할 수 없습니다.
너도 원한다고 했잖아목록*.e*
"추가 처리"와 일치하는 파일입니다. 이 작업을 수행하는 대신 find
실제 명령 자체에서 수행하는 것이 좋습니다 . 그 이유는 질문/답변에 나와 있습니다.찾기 결과를 반복하는 것이 왜 나쁜 습관입니까?".
그러니 지금 무엇을 하고 있는지 생각하지 마세요.
find . -type f -name md.tpr -exec bash -O nullglob -O dotglob -c '
for pathname do
dirpath=${pathname%/md.tpr}
for e in "$dirpath"/*.e*; do
# process "$e" here!
done
done' bash {} +
이는 md.tpr
일반 파일을 찾아야 한다고 가정합니다. 이 find
명령은 이러한 모든 파일의 경로 이름을 찾아 일괄적으로 md.tpr
인라인 bash
스크립트에 제공합니다. 스크립트는 bash
매우 짧습니다.
for pathname do
dirpath=${pathname%/md.tpr}
for e in "$dirpath"/*.e*; do
# process "$e" here!
done
done
이는 단순히 주어진 인수를 취하고, 각 디렉토리의 구성 요소를 추출하고( 우리가 알고 있는 접미사 문자열을 경로 이름에 제거하여) 각 디렉토리에서 일치하는 파일을 /md.tpr
반복합니다 ( 각 일치하는 파일의 경로 이름을 차례로 저장).*.e*
$e
인라인 스크립트는 패턴이 일치하지 않으면 완전히 제거되고 패턴이 숨겨진 이름과 일치하도록 nullglob
및 dotglob
옵션이 설정된 상태 로 실행됩니다.*.e*
-exec
with 사용에 대한 자세한 내용 find
은 ""find"의 -exec 옵션 이해".
이 질문에 태그를 지정했으므로세게 때리다, 일반 루프에서 동일한 작업을 수행하는 방법은 다음과 같습니다 bash
( bash
버전 4 이상이 필요함).
shopt -s globstar nullglob dotglob
for pathname in ./**/md.tpr; do
dirpath=${pathname%/md.tpr}
for e in "$dirpath"/*.e*; do
# process "$e" here!
done
done
이는 일치하는 파일이 일반 파일인지 확인하지 않는다는 점을 제외하면 md.tpr
위에서 호출한 인라인 스크립트와 매우 유사해 보입니다 find
. 쉘 globstar
옵션은 하위 디렉토리를 "재귀적으로" 일치시키는 glob을 bash
활성화합니다 .**
를 사용하는 것보다 약간 느릴 것으로 예상되지만 find
코드를 작성하는 데 더 편리한 방법일 수 있습니다.