Programing

xargs가 공백이 포함 된 파일 이름을 처리하도록 설정

lottogame 2020. 4. 18. 09:29
반응형

xargs가 공백이 포함 된 파일 이름을 처리하도록 설정


$ ls *mp3 | xargs mplayer  

Playing Lemon.  
File not found: 'Lemon'  
Playing Tree.mp3.  
File not found: 'Tree.mp3'  

Exiting... (End of file)  

"Lemon Tree.mp3"파일에 공백이 포함되어 있으므로 xargs는 두 파일이라고 생각하기 때문에 명령이 실패합니다. find + xargs가 이와 같은 파일 이름으로 작동하도록 할 수 있습니까?


xargs명령은 공백 문자 (탭, 공백, 줄 바꾸기)를 구분 기호로 사용합니다. 다음과 -d같은 옵션 을 사용하여 줄 바꾸기 문자 ( '\ n')에 대해서만 범위를 좁힐 수 있습니다 .

ls *.mp3 | xargs -d '\n' mplayer

GNU xargs에서만 작동합니다. BSD 시스템의 경우 다음 -0과 같은 옵션을 사용하십시오 .

ls *.mp3 | xargs -0 mplayer

이 방법은 더 간단하며 GNU xargs에서도 작동합니다.


xargs 유틸리티는 표준 입력에서 공백, 탭, 줄 바꿈 및 파일 끝으로 구분 된 문자열을 읽고 문자열을 인수로 사용하여 유틸리티를 실행합니다.

공백을 구분 기호로 사용하지 않으려 고합니다. 이는 xargs의 분리 문자를 변경하여 수행 할 수 있습니다. 매뉴얼에 따르면 :

 -0      Change xargs to expect NUL (``\0'') characters as separators,
         instead of spaces and newlines.  This is expected to be used in
         concert with the -print0 function in find(1).

같은 :

 find . -name "*.mp3" -print0 | xargs -0 mplayer

일곱 번째 mp3 재생에 관한 질문에 대답하기 위해; 실행하는 것이 더 간단합니다

 mplayer "$(ls *.mp3 | sed -n 7p)"

시험

find . -name \*.mp3 -print0 | xargs -0 mplayer

대신에

ls | grep mp3 

MacOS의 xargs에는 -d 옵션이 없으므로이 솔루션은 대신 -0을 사용합니다.

ls가 한 줄에 하나의 파일을 출력하도록 한 다음 개행을 널로 변환하고 xargs에 널을 분리 문자로 사용하도록 지시하십시오.

ls -1 *mp3 | tr "\n" "\0" | xargs -0 mplayer


Dick.Guertin의 답변 [1]은 파일 이름에서 공백을 이스케이프 처리 할 수있는 방법이 여기에 제안 된 다른 솔루션을 대체 할 수있는 귀중한 대안이라고 제안했습니다 (예 : 공백 대신 null 문자를 구분 기호로 사용). 그러나 더 간단 할 수 있습니다-당신은 정말로 독특한 캐릭터가 필요하지 않습니다. sed는 이스케이프 된 공백을 직접 추가 할 수 있습니다.

ls | grep ' ' | sed 's| |\\ |g' | xargs ...

또한 grep은 이름에 공백이있는 파일 원하는 경우에만 필요 합니다. 보다 일반적으로 (예를 들어, 공백이있는 파일을 처리 할 때 일부는 공백이 아닌 경우) grep을 건너 뛰십시오.

ls | sed 's| |\\ |g' | xargs ...

그런 다음 파일 이름에 공백이 아닌 다른 공백 (예 : 탭)이있을 수 있습니다.

ls | sed -r 's|[[:blank:]]|\\\1|g' | xargs ...

즉, GNU sed 또는 최신 버전의 bsd sed와 같은 -r (확장 정규식)을 지원하는 sed가 있다고 가정합니다 (예 : FreeBSD 8 이전에 "-E"옵션의 철자를 사용한 FreeBSD와 호환성을 위해 -r & -E 모두 지원) 적어도 FreeBSD 11을 통해). 그렇지 않으면 기본 정규식 문자 클래스 대괄호 표현식을 사용하고 []구분 기호 에 공백과 탭 문자를 수동으로 입력 할 수 있습니다 .

[1]이 답변에 대한 의견이나 수정 사항으로 더 적합 할 수도 있지만 현재로서는 의견을 평가할만한 충분한 평판이 없으며 수정 사항 만 제안 할 수 있습니다. 후자의 형태는 (그렙없이) Dick.Guertin의 원래 답변을 변경하기 때문에 직접 편집하는 것은 적절하지 않습니다.


find . -name 'Lemon*.mp3' -print0 | xargs -­0 -i mplayer '{}' 

이것은 내 경우 공백이있는 다른 파일을 삭제하는 데 도움이되었습니다. mplayer에서도 작동합니다. 필요한 트릭은 따옴표입니다. (Linux Xubuntu 14.04 에서 테스트되었습니다 .)


ls | grep mp3 | sed -n "7p" | xargs -i mplayer {}

위 명령 에서 각 파일에 대해 새로 xargs호출 mplayer합니다. 이는 바람직하지 mplayer않지만 다른 대상에는 적합 할 수 있습니다.


macOS 10.12.x (Sierra)에서 파일 이름 또는 하위 디렉토리에 공백이 있으면 다음을 사용할 수 있습니다.

find . -name '*.swift' -exec echo '"{}"' \; |xargs wc -l

(a) 레몬과 달리 숫자 7에 어떻게 연결되어 있는지, (b) 파일 이름에 줄 바꿈이 포함되어 있는지 여부 및 파일 이름이 바뀌면 기꺼이 바꿀지 여부에 따라 다릅니다.

여러 가지 방법으로 처리 할 수 ​​있지만 그 중 일부는 다음과 같습니다.

mplayer Lemon*.mp3

find . -name 'Lemon*.mp3' -exec mplayer {} ';'

i=0
for mp3 in *.mp3
do
    i=$((i+1))
    [ $i = 7 ] && mplayer "$mp3"
done

for mp3 in *.mp3
do
    case "$mp3" in
    (Lemon*) mplayer "$mp3";;
    esac
done

i=0
find . -name *.mp3 |
while read mp3
do
    i=$((i+1))
    [ $i = 7 ] && mplayer "$mp3"
done

read파일 이름이 개행 문자가 포함 된 경우 루프가 작동하지 않습니다; 다른 것들은 이름의 개행으로도 올바르게 작동합니다 (공백 제외). 내 돈을 위해 줄 바꿈이 포함 된 파일 이름이 있으면 줄 바꿈없이 파일 이름을 바꿔야합니다. 루프가 올바르게 작동하려면 파일 이름을 큰 따옴표로 묶어야합니다.

GNU find및 GNU xargs(또는 FreeBSD (* BSD?) 또는 Mac OS X)가있는 경우 다음 -print0같이 -0옵션을 사용할 수 있습니다 .

find . -name 'Lemon*.mp3' -print0 | xargs -0 mplayer

이름의 내용에 관계없이 작동합니다 (파일 이름에 표시 할 수없는 두 문자 만 슬래시와 NUL이며 슬래시는 파일 경로에 문제를 일으키지 않으므로 이름 구분 기호로 NUL을 사용하면 모든 것을 다룹니다). 그러나 처음 6 개 항목을 필터링 해야하는 경우 줄 바꿈 대신 NUL로 끝나는 '줄'을 처리하는 프로그램이 필요합니다 ... 그리고 확실하지 않습니다.

첫 번째는 현재 진행중인 특정 사례에서 가장 단순합니다. 그러나 아직 나열하지 않은 다른 시나리오는 다루지 않을 수 있습니다.


나는 xargs질문에 직접 대답 하지는 않지만 find-exec옵션을 언급 할 가치가 있음을 알고 있습니다.

다음과 같은 파일 시스템이 제공됩니다.

[root@localhost bokeh]# tree --charset assci bands
bands
|-- Dream\ Theater
|-- King's\ X
|-- Megadeth
`-- Rush

0 directories, 4 files

find 명령은 Dream Theater와 King 's X의 공간을 처리하도록 만들 수 있습니다. 따라서 grep을 사용하여 각 밴드의 드러머를 찾으십시오.

[root@localhost]# find bands/ -type f -exec grep Drums {} +
bands/Dream Theater:Drums:Mike Mangini
bands/Rush:Drums: Neil Peart
bands/King's X:Drums:Jerry Gaskill
bands/Megadeth:Drums:Dirk Verbeuren

에서 -exec옵션 {}경로를 포함한 파일 이름을 의미합니다. 이스케이프하거나 따옴표로 묶을 필요는 없습니다.

-exec종료 자 ( +\;) 의 차이점은 +하나의 명령 줄에 가능한 많은 파일 이름을 그룹화한다는 것입니다. 반면 \;각 파일 이름에 대한 명령을 실행합니다.

따라서 find bands/ -type f -exec grep Drums {} +결과는 다음과 같습니다.

grep Drums "bands/Dream Theater" "bands/Rush" "bands/King's X" "bands/Megadeth"

find bands/ -type f -exec grep Drums {} \;결과는 다음 같습니다.

grep Drums "bands/Dream Theater"
grep Drums "bands/Rush"
grep Drums "bands/King's X"
grep Drums "bands/Megadeth"

이 경우 grep파일 이름 인쇄 여부에 따른 부작용이 있습니다.

[root@localhost bokeh]# find bands/ -type f -exec grep Drums {} \;
Drums:Mike Mangini
Drums: Neil Peart
Drums:Jerry Gaskill
Drums:Dirk Verbeuren

[root@localhost bokeh]# find bands/ -type f -exec grep Drums {} +
bands/Dream Theater:Drums:Mike Mangini
bands/Rush:Drums: Neil Peart
bands/King's X:Drums:Jerry Gaskill
bands/Megadeth:Drums:Dirk Verbeuren

물론, grep'옵션을이야 -h-H파일 이름에 관계없이 어떻게 인쇄할지 여부를 제어합니다 grep라고합니다.


xargs

xargs 명령 행에서 man 파일이있는 방법을 제어 할 수도 있습니다.

xargs기본적으로 모든 인수는 한 줄로 그룹화됩니다. -exec \;사용 하는 것과 동일한 작업을 수행합니다 xargs -l. -t옵션은 xargs명령을 실행하기 전에 인쇄하도록 지시 합니다.

[root@localhost bokeh]# find ./bands -type f  | xargs -d '\n' -l -t grep Drums
grep Drums ./bands/Dream Theater 
Drums:Mike Mangini
grep Drums ./bands/Rush 
Drums: Neil Peart
grep Drums ./bands/King's X 
Drums:Jerry Gaskill
grep Drums ./bands/Megadeth 
Drums:Dirk Verbeuren

-l옵션은 xargs가 모든 파일 이름에 대해 grep을 실행하도록 지시합니다.

기본값 대 ( -l옵션 없음 ) :

[root@localhost bokeh]# find ./bands -type f  | xargs -d '\n'  -t grep Drums
grep Drums ./bands/Dream Theater ./bands/Rush ./bands/King's X ./bands/Megadeth 
./bands/Dream Theater:Drums:Mike Mangini
./bands/Rush:Drums: Neil Peart
./bands/King's X:Drums:Jerry Gaskill
./bands/Megadeth:Drums:Dirk Verbeuren

xargs명령 줄에 몇 개의 파일이 있는지 더 잘 제어 할 수 있습니다. -l옵션 당 명령 당 최대 파일 수를 제공하십시오 .

[root@localhost bokeh]# find ./bands -type f  | xargs -d '\n'  -l2 -t grep Drums
grep Drums ./bands/Dream Theater ./bands/Rush 
./bands/Dream Theater:Drums:Mike Mangini
./bands/Rush:Drums: Neil Peart
grep Drums ./bands/King's X ./bands/Megadeth 
./bands/King's X:Drums:Jerry Gaskill
./bands/Megadeth:Drums:Dirk Verbeuren
[root@localhost bokeh]# 

grep때문에 두 개의 파일 이름으로 실행 되었음을 참조하십시오 -l2.


이 게시물의 특정 제목을 감안할 때 다음은 내 제안입니다.

ls | grep ' ' | tr ' ' '<' | sed 's|<|\\ |g'

아이디어는 공백을 '<'와 같은 고유 문자로 변환 한 다음 백 슬래시와 공백을 '\'로 변경하는 것입니다. 그런 다음 다음과 같이 원하는 명령으로 파이프 할 수 있습니다.

ls | grep ' ' | tr ' ' '<' | sed 's|<|\\ |g' | xargs -L1 GetFileInfo

여기서 핵심은 'tr'및 'sed'명령에 있습니다. '?'와 같이 '<'이외의 문자를 사용할 수 있습니다. 또는 탭 문자.


대체 솔루션이 도움이 될 수 있습니다 ...

Perl을 사용하여 줄 끝에 널 문자를 추가 한 다음 -0xargs 옵션 을 사용할 수도 있습니다. xargs -d '\ n'(승인 된 답변)과 달리 이것은 OS X를 포함한 모든 곳에서 작동합니다.

예를 들어 공백이나 다른 재미있는 문자가 포함될 수있는 JPEG 이미지를 재귀 적으로 나열 (실행, 이동 등)하려면 다음을 사용합니다.

find . | grep \.jpg | perl -ne 'chop; print "$_\0"' | xargs -0  ls

(참고 : 필터링의 경우 "find 's"--name 인수보다 기억하기 쉬운 "| grep"구문을 선호합니다.

참고 URL : https://stackoverflow.com/questions/16758525/make-xargs-handle-filenames-that-contain-spaces

반응형