'find'결과를 파일 목록으로 전달하는 방법은 무엇입니까?


11

상황은 mpg321파일 목록을 인수로 허용 하는 MP3 플레이어 가 있습니다. 나는 "music"이라는 디렉토리에 음악을 보관하는데 여기에는 몇 개의 디렉토리가 더있다. 난 그냥 그들 모두를 재생하고 싶어, 그래서 나는 프로그램을 실행

mpg321 $(find /music -iname "*\.mp3")

. 문제는 일부 파일 이름에 공백이 있고 프로그램이 해당 이름을 작은 부분으로 나누고 누락 된 파일에 대해 불평한다는 것입니다. find따옴표로 결과 감싸기

mpg321 "$(find /music -iname "*\.mp3")"

모든 것이 하나의 큰 "파일 이름"이되기 때문에 도움이되지 않습니다.

그러면 어떻게해야합니까? 그것이 중요하다면, 나는 사용 bash하고 있지만 zsh곧 전환 할 것입니다.

답변:


17

찾기 -print0또는 -printf옵션을 다음과 xargs같이 사용하십시오.

find /music -iname "*\.mp3" -print0 | xargs -0 mpg321

작동 방식은 find의 매뉴얼 페이지에 설명되어 있습니다 .

-print0

진실; 표준 출력에 전체 파일 이름을 인쇄하고 그 뒤에 널 문자 (-print가 사용하는 줄 바꾸기 문자 대신)를 입력하십시오. 이렇게하면 개행 또는 다른 유형의 공백이 포함 된 파일 이름을 찾기 출력을 처리하는 프로그램에서 올바르게 해석 할 수 있습니다. 이 옵션은 xargs의 -0 옵션에 해당합니다.


모든 편집에 대해 죄송합니다. 다른 유형의 공백에서 실패하는 -print0 xarg -0 패턴을 기억하는 것 같지만 예제를 찾을 수 없었습니다.
Steven D

아 맞다! 그래도 왜 안 mpg321 $(find /music -iname "*\.mp3" -print0)그래?
phunehehe

1
글쎄, 나는 두 가지 이유로 작동하지 않는다고 생각한다 : (1) 파일 이름은 널 문자로 분리되어 mpg321이 전혀 기대하지 않는 것과 (2) xargs는 다른 공백을 피하는 작업을하지 않습니다. 찾기.
Steven D

2
@phunehehe, @Steven : mpg321그것과 아무 관련이 없습니다. 그것은 find별도의 인수로 출력을 나누는 쉘입니다 . 그리고 -print0 | xargs -0가능한 모든 파일 이름으로 작동합니다.
Gilles 'SO- 악마 그만

8
find /music -iname "*\.mp3" -exec mpg123 {} +

GNU find를 사용하면 -print0xargs -0 을 사용할 수 있지만 또 다른 도구를 배우는 데는 별다른 의미가 없습니다. -exec ... {} +리눅스 나중에 이상을 취득한 때문에 구문은 약간의 언급을 가져옵니다 -print0,하지만 지금은 그것을 사용하지 않을 이유가 없습니다.

zsh 또는 bash 4를 사용하면 훨씬 간단합니다.

mpg123 **/*.[Mm][Pp]3

zsh에서만 (a의 일부) 패턴을 대소 문자를 구분하지 않게 만들 수 있습니다.

mpg123 (#i)**/*.mp3

+1로 "find -print0"은 못생긴 해킹입니다.
p-static

2

Steven의 해결책 이 최선 이라고 생각 하지만 다른 방법은 xargs ' -I플래그 를 사용 하는 것입니다.이 문자열을 사용하면 명령에서 인수로 바꿀 문자열을 지정할 수 있습니다 (명령 끝에 인수를 추가하는 대신). 이를 사용하여 인수를 인용 할 수 있습니다.

find /music -iname "*\.mp3" | xargs -0 -Ifoo mpg321 "foo"

이 답변을 이해하지 못합니다 ... -0find 's없이 xargs의 플래그를 사용하고 -print0있습니다. 또한 xargs의 -I플래그에는 여러 가지 결과가 있습니다. 그냥 일반 달리 xargs한 명령에서 표준 입력에서 라인을 모두 압축되는, xargs -I실행할 mpg321가능성이 확실히 의도하지 않습니다 (각 파일에 대해 한 번) 시간의 수백 또는 수천. 또한 xargs내부적 으로 foo를 인용하는 것은 불필요하다는 것을 명심하십시오 . 모든 파일 이름을 줄로 압축하여로 보내면 xargs -I열리지 않습니다.
6

1

일반적으로 직접 작성하는 -exec ${tgt_process} \{\} +것이 가장 좋지만 어떤 이유로 든 파일 또는 스트림에서 파일 이름의 파일 목록을 안정적으로 구분 해야하는 경우 find다음을 수행 할 수 있습니다.

find -exec sh -c 'printf "///%s///\n" "$@"' -- \{\} +

그로부터 얻는 것은 두 개의 고유 한 문자열입니다. 모든 파일 이름의 맨 앞에는 문자열이 \n///있고 모든 파일 이름의 맨 끝에는 문자열이 ///\n있습니다. 이 두 문자열은 find파일 이름에 포함 된 문자에 관계없이 해당 위치를 제외하고의 출력 에서 다른 곳에서는 발생하지 않습니다 .

또한 위의 사용법은 기본 POSIX 휴대용이며 거의 모든 유닉스 시스템에서 작동 할 수 있습니다. 편리함에도 불구하고 널 바이트 분리 문자를 사용하는 경우에는 그렇지 않습니다.

당신이 직접적으로 수 없다면, 다시, 이것은 단지 필요가 -exec당신 $tgt_process을 위해 그 당신의 목표가되어야로 어떤 이유. 우선, 위의 방법은 여전히 ​​구문 분석이 필요합니다. 예를 들어, 각 파일 이름 셸을 인용하려면 먼저 파일 이름의 하드 따옴표를 이스케이프해야합니다.

find ... + | sed 's|'\''|&"&"&|g;s|///|'\''|g'

구성 문자가 무엇이든 관계없이 셸 이스케이프 처리 된 파일 이름 배열을 출력합니다. 이제 수신 측의 응용 프로그램이 엉망이되지 않기를 바랍니다.


0

이 작업을 수행하는 또 다른 방법은 파일 이름에 나오는 모든 특수 문자를 이스케이프 처리하는 것입니다. 예 :

find /music -iname "*\.mp3" | sed 's!\([] \*\$\/&[]\)!\\\1!g' | xargs mpg321

이것은 기본적으로 제대로 이스케이프 된 파일 이름을 xargs에 전달하여 실행되며 아무런 문제가 없습니다.


1
여전히 파일 이름의 줄 바꿈이 끊어집니다. 그리고 수도뿐만 아니라 단지 sed 's|.|\\&|g'- POSIX 어쨌든 권장 무엇을 그.
mikeserv
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.