파일 이름을 다른 프로그램으로 파이프하고 싶지만 이름에 공백이 있으면 모두 막힙니다.
라는 파일이 있다고 가정 해 봅시다.
foo bar
find
올바른 이름을 어떻게 반환할 수 있나요 ?
분명히 내가 원하는 것은:
foo\ bar
또는:
"foo bar"
편집하다:나는 그런 일을 겪고 싶지 않습니다 . 파일 이름 문자열을 다른 프로그램으로 직접 파이프할 수 있도록 xargs
올바른 형식의 문자열을 얻고 싶습니다 .find
답변1
앞쪽:
find . -type f -exec sh -c '
for f do
: command "$f"
done
' sh {} +
find
다음에 대한 지원 -print0
과 xargs
지원이 있습니다 -0
.
find . -type f -print0 | xargs -0 <command>
-0
옵션은 xargs에게 공백 대신 ASCII NUL 문자를 사용하여 (별도의) 파일 이름을 종료하도록 지시합니다.
예:
find . -maxdepth 1 -type f -print0 | xargs -0 ls -l
답변2
사용 은 옵션이지만 모든 프로그램이 널 바이트로 구분된 데이터 스트림 사용을 지원하는 것은 아니므로 Gnouc의 답변에 명시된 대로 -print0
어떤 경우에는 xargs
해당 옵션을 사용해야 합니다.-0
find
또 다른 옵션은 ' -exec
또는 옵션을 사용하는 것입니다 -execdir
. 다음 중 첫 번째는 somecommand
한 번에 하나씩 파일 이름을 제공하고 두 번째는 파일 목록으로 확장됩니다.
find . -type f -exec somecommand '{}' \;
find . -type f -exec somecommand '{}' +
많은 상황에서 와일드카드를 사용하는 것이 더 낫다는 것을 알 수 있습니다. 최신 셸(bash 4+, zsh, ksh)을 사용하는 경우 재귀적 글로빙에 globstar
( **
)를 사용할 수 있습니다. Bash에서는 다음과 같이 설정해야 합니다.
shopt -s globstar
somecommand ./**/*.txt ## feeds all *.txt files to somecommand, recursively
내 .bashrc에 라인이 있어서 shopt -s globstar extglob
항상 활성화되어 있습니다(확장 glob도 도움이 됩니다).
재귀를 원하지 않으면 ./*.txt
작업 디렉토리의 모든 *.txt를 사용하십시오. find
매우 유용한 세분화된 검색 기능이 있으며 수만 개의 파일에 필요하지만(이 시점에서 쉘의 최대 인수 수에 도달하게 됩니다) 일상적인 사용에는 일반적으로 필요하지 않습니다.
답변3
따라서 이를 사용하고 싶지 않은 경우 xargs
(따라서 아마도 사용하고 싶지 않은 경우 parallel
) find
다음과 같이 출력을 한 줄씩 읽고 처리할 수 있습니다.
find . -type f | while read x; do
# do something with $x
done
답변4
-exec
개인적으로 저는 이러한 문제를 해결하기 위해 찾기 작업을 사용합니다 . 또는 필요한 경우 xargs
병렬 실행을 허용합니다 .
find
그러나 bash에서 읽을 수 있는 파일 이름 목록을 생성 하는 방법이 있습니다 . 놀랍지 않게 -exec
도 and bash
, 특히 명령 확장을 사용합니다 printf
.
find ... -exec bash -c 'printf "%q " "$@"' printf {} ';'
그러나 이는 쉘 이스케이프 단어를 올바르게 인쇄하지만 따옴표나 이스케이프가 해석되지 않기 $(...)
때문에 와 함께 사용할 수 없습니다. $(...)
(따옴표로 묶지 않으면 단어 분리 및 경로 이름 확장의 결과가 $(...)
영향을 받습니다.) 따라서 다음은 원하는 대로 작동하지 않습니다.
ls $(find ... -exec bash -c 'printf "%q " "$@"' printf {} +)
당신이 해야 할 일은:
eval "ls $(find ... -exec bash -c 'printf "%q " "$@"' printf {} +)"
(실제로 위의 몬스터들을 테스트해보지는 않았음을 참고해주세요.)
하지만 다음과 같이 할 수도 있습니다.
find ... -exec ls {} +