파일 이름에 공백이 있으면 find를 어떻게 사용합니까?


17

파일 이름을 다른 프로그램으로 파이프하고 싶지만 이름에 공백이 있으면 모두 질식합니다.

파일이 있다고 가정 해 봅시다.

foo bar

find올바른 이름을 반환하려면 어떻게 해야합니까?

분명히 나는 ​​원한다.

foo\ bar

또는:

"foo bar"

편집 : 통과하고 싶지 않아 xargs, find파일 이름 문자열을 다른 프로그램으로 직접 파이프 할 수 있도록 올바른 형식의 문자열을 가져오고 싶습니다 .


5
무엇을 배관합니까? -exec와 플래그 를 알고 find있습니까? 잠재적으로이 오류를 완화하고 -exec다른 명령으로 파이프 하는 대신 명령을보다 효율적으로 수행 할 수 있습니다. 그냥 내 $ .02
h3rrmiller 15:56에

6
@bug : find파일 이름의 형식을 정확하게 지정합니다. 그들은 한 줄에 하나의 이름으로 작성됩니다. (물론, 파일 이름에 줄 바꿈 문자가 포함되어 있으면 모호합니다.) 따라서 문제는 공백이 생겼을 때 수신 끝 "질식"입니다. 즉, 의미있는 답변을 원할 경우 수신 끝이 무엇인지 알려 주어야합니다. .
rici

2
"올바른 형식"이라고 부르는 것은 실제로 "쉘이 소비하기 위해 탈출 한 것"입니다. 많은 파일 이름을 읽을 수있는 대부분의 유틸리티는 쉘 이스케이프 된 이름에서 질식하지만 실제로는 find파일 이름을 쉘에 적합한 형식으로 출력하는 옵션을 제공하는 것이 합리적입니다 . 그러나 일반적으로 -print0GNU find확장은 다른 많은 시나리오에서도 잘 작동하므로 어떤 경우에도 사용하는 방법을 배워야합니다.
tripleee

2
@bug : 그건 그렇고, ls $(command...)목록을 통해 피드하지 않습니다 stdin. $(command...)명령 행 에 직접 출력을 넣습니다 . 이 경우 c에서 읽는 쉘이며 현재 값을 사용 $IFS하여 출력을 워드 분할하는 방법을 결정합니다. 일반적으로을 사용하는 것이 좋습니다 xargs. 성능 저하를 느끼지 못할 것입니다.
rici

2
find -printf '"%p"\n'찾은 각 이름 주위에 큰 따옴표를 추가하지만 파일 이름에 큰 따옴표를 올바르게 인용하지 않습니다. 파일 이름에 큰 따옴표가 포함되어 있지 않으면 문제를 무시하거나 다음을 통해 파이프 할 수 있습니다 sed 's/"/&&/g;s/^""/"/;s/""$/"/'. 파일 이름이 셸에 의해 처리되는 경우 큰 따옴표 대신 작은 따옴표를 사용해야합니다 (그렇지 sweet$HOME않으면와 같음 sheet/home/you). 그리고 이것은 줄 바꿈이있는 파일 이름에 대해서는 여전히 강력하지 않습니다. 어떻게 처리하고 싶습니까?
tripleee

답변:


18

POSIXLY :

find . -type f -exec sh -c '
  for f do
    : command "$f"
  done
' sh {} +

find지원 -print0xargs지원 -0:

find . -type f -print0 | xargs -0 <command>

-0 옵션은 xargs가 파일 이름을 끝내기 위해 공백 대신 ASCII NUL 문자를 사용하도록 지시합니다.

예:

find . -maxdepth 1 -type f -print0 | xargs -0 ls -l

작동하지 않습니다. 내가 실행할 때 ls $(find . -maxdepth 1 -type f -print0 | xargs -0)내가 얻을 ls: cannot access ./foo: No such file or directory ls: cannot access bar: No such file or directory
버그

1
Gnouc이 실제로 쓴 방식으로 시도해 보셨습니까? 당신이 당신의 방식으로 그것을 주장한다면, $(..)큰 따옴표로 "$(..)"
묶어

3
@bug : 명령이 잘못되었습니다. 정확히 내가 worte을 시도하고의 맨 페이지를 읽어 findxargs.
cuonglm

나는 다시 파이프 할 수있는 형식화 된 문자열을 얻고 싶다.
bug

1
@bug : 그냥 xargs -0 <프로그램>을 사용하십시오
cuonglm

10

사용 -print0은 하나의 옵션이지만 모든 프로그램이 널 바이트로 구분 된 데이터 스트림 사용을 지원하지는 않으므로 Gnouc의 답변에서 언급했듯이 일부 옵션 을 사용해야 xargs합니다 -0.

대안은 사용하는 것입니다 find-exec또는 -execdir옵션. 다음 중 첫 번째는 파일 이름을 somecommand한 번에 하나씩 제공하고 두 번째는 파일 목록으로 확장합니다.

find . -type f -exec somecommand '{}' \;
find . -type f -exec somecommand '{}' +

많은 경우 글러브를 사용하는 것이 더 나을 수 있습니다. 최신 쉘 (bash 4+, zsh, ksh)이 있으면 globstar( **)을 사용 하여 재귀 적 globbing을 얻을 수 있습니다 . bash에서는 다음을 설정해야합니다.

shopt -s globstar
somecommand ./**/*.txt ## feeds all *.txt files to somecommand, recursively

shopt -s globstar extglob내 .bashrc에 줄 이 표시되어있어 항상 사용할 수 있습니다 (그리고 확장 된 globs도 유용합니다).

재귀를 원하지 않으면 ./*.txt작업 디렉토리의 모든 * .txt를 사용 하는 대신 분명히 사용 하십시오. find매우 유용한 세분화 된 검색 기능이 있으며 수만 개의 파일 (필수 시점에서 셸의 최대 인수 수에 도달해야 함)에 필수적이지만 일상적인 사용에는 종종 불필요합니다.


안녕하세요 @evilsoup이 스크립트에서 {}의 기능은 무엇입니까?
Ayusman

3

개인적으로 -exec이런 종류의 문제를 해결하기 위해 찾기 작업을 사용합니다 . 또는 필요한 경우 xargs병렬 실행을 허용합니다.

그러나 findbash로 읽을 수있는 파일 이름 목록을 생성 하는 방법이 있습니다. 당연히, -exec그리고 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 {} +

ls시나리오가 OP의 유스 케이스를 적절하게 포착 한다고 생각하지는 않지만 실제로 수행하려고하는 것을 보여주지 않았기 때문에 이것은 추측 일뿐입니다. 이 솔루션은 실제로 매우 훌륭하게 작동합니다. 내가 시도한 모든 재미있는 파일 이름에 대해 (모호하게) 예상되는 결과를 얻습니다.touch "$(tr a-z '\001-\026' <<<'the quick brown fox jumped over the lazy dogs')"
tripleee

@triplee : OP가 무엇을 원하는지 전혀 모른다. 따옴표로 묶은 문자열을 전달할 수있는 유일한 장점은 아직 eval전달할 필요가 없다는 것입니다 eval. 매개 변수에 저장하고 나중에 다른 명령으로 여러 번 사용할 수 있습니다. 그러나 OP는 이것이 유스 케이스라는 것을 나타내지 않습니다. (그렇다면 까다
롭지

0
find ./  | grep " "

파일과 디렉토리에 공백이 있습니다.

find ./ -type f  | grep " " 

파일에 공백이 포함되어 있습니다.

find ./ -type d | grep " "

디렉토리에 공백이 있습니다.


-2
    find . -type f -name \*\  | sed -e 's/ /<thisisspace>/g'

이것은 흥미로운 답변이지만이 질문에 대한 답변은 아닙니다.
Scott
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.