xargs는 언제 필요합니까?


134

xargs명령은 항상 혼란스러워합니다. 그것에 대한 일반적인 규칙이 있습니까?

아래 두 가지 예를 고려하십시오.

$ \ls | grep Cases | less

'Cases'와 일치하는 파일을 인쇄하지만 명령을 변경 touch하려면 xargs다음 이 필요합니다 .

$ \ls | grep Cases | touch
touch: missing file operand
Try `touch --help' for more information.

$ \ls | grep Cases | xargs touch

답변:


143

차이점은 대상 프로그램이 수용하는 데이터에 있습니다.

파이프 만 사용하는 경우 STDIN (표준 입력 스트림)의 데이터를 한 번에 한 줄씩 정렬 할 수있는 원시 데이터 더미로 수신합니다. 그러나 일부 프로그램은 표준으로 명령을 수락하지 않으며 명령에 대한 인수에서 철자를 기대합니다. 예를 들어 touch, 명령 행에서 다음과 같이 파일 이름을 매개 변수로 사용합니다 touch file1.txt.

당신은 파일 이름을 출력하는 프로그램이 있으면 밖으로 표준을 하고 사용하려는 인자로touch, 당신은 사용해야하는 xargs표준 입력 스트림 데이터를 읽고 명령을 공백으로 구분 인수로 각 라인을 변환한다.

이 두 가지는 동일합니다.

# touch file1.txt
# echo file1.txt | xargs touch

xargs정확히 무엇을하고 있고 왜 필요한지 알지 않는 한 사용 하지 마십시오 . xargs변환을 강제하는 데 사용 하는 것보다 작업을 수행하는 더 좋은 방법이있는 경우가 종종 있습니다. 변환 과정에는 탈출과 단어 확장 등과 같은 잠재적 인 함정이 있습니다.


2
경고는 나에게 약간의 끈을 느낀다. 명령 행 ( xargs$(...)) 으로 스트림을 가져 오는 두 가지 일반적인 옵션 중에서 xargs는 명령 대체보다 훨씬 안전합니다. 그리고 줄 바꿈이있는 합법적 인 파일 이름을 발견 한 것을 기억할 수 없습니다. 이스케이프 및 단어 확장 함정이 xargs가 아닌 명령 대체와 관련이 있습니까?
camh

6
@ camh : 둘 다 잠재적 인 함정입니다. 셸에서는 파일 이름이 공백, 탭 및 줄 바꿈으로 분할되는 것에 대해 걱정해야합니다. xargs에서는 개행에 대해서만 걱정하면됩니다. xargs에서 출력 형식이 올 바르면 대신 NUL 문자에서 단어 / 파일 이름을 분할 할 수 있습니다 ( xargs -0) find -print0.
Ken Bloom

xargs공백으로 구분 된 args로 쉘을 통해 프로그램을 호출 합니까 , 아니면 실제로 내부적으로 인수 목록을 구성 합니까 (예 : execv/ 와 함께 사용 execp)?
detly

1
내부적으로 구성하고 execvp를 사용하므로 안전합니다. 또한 -d \nBSD xargs (OSX et al)는이 옵션을 지원하지 않는 것처럼 보이지만 GNU xargs (Linux 및 기타 몇 가지에서 사용됨)를 사용하면 구분 기호로 줄 바꿈을 지정할 수 있습니다 .
푹신한

72

이미 제공된 답변을 확장하려면 xargs오늘날의 멀티 코어 및 분산 컴퓨팅 환경에서 점점 중요 해지고있는 멋진 일을 처리 할 수 ​​있습니다. 프로세스 작업을 병렬 처리 할 수 ​​있습니다.

예를 들면 다음과 같습니다.

$ find . -type f -name '*.wav' -print0 |xargs -0 -P 3 -n 1 flac -V8

한 번에 세 개의 프로세스를 사용하여 * .wav => * .flac를 인코딩합니다 ( -P 3).


와. 일주일 전에 50GiB의 WAV와 똑같은 일을 할 때 (OGG 사용 제외) 알았을 것입니다. :)
Alois Mahdal

찾은 -exec 매개 변수를 사용하지 않는 이유는 무엇입니까?
Evgeny

3
@Evgeny이 -exec매개 변수는 작업을 병렬 처리하지 않습니다.
amphetamachine

-0인수가xargsNULL 문자를 입력 항목 분리 문자로 간주하도록 하는 인수 에 유의하십시오 . find -print0NULL로 구분 된 항목을 출력합니다. 공백, 따옴표 또는 기타 특수 문자를 포함 할 수있는 파일 이름에 유용합니다.
Dan Dascalescu

24

xargs는 stdin에 파일 경로 목록이 있고 그와 함께 무언가를 수행하려고 할 때 특히 유용합니다. 예를 들면 다음과 같습니다.

$ git ls-files "*.tex" | xargs -n 1 sed -i "s/color/colour/g"

이 단계를 단계별로 살펴 보자.

$ git ls-files "*.tex"
tex/ch1/intro.tex
tex/ch1/motivation.tex
....

다시 말해, 우리의 입력은 우리가하고 싶은 경로의 목록입니다.

이러한 경로에서 xargs가 수행하는 작업을 찾으 echo려면 명령 앞에 다음과 같이 추가하는 것이 좋습니다 .

$ git ls-files "*.tex" | xargs -n 1 echo sed -i "s/color/colour/g"
sed -i "s/color/colour/g" tex/ch1/intro.tex
sed -i "s/color/colour/g" tex/ch1/motivation.tex
....

-n 1인수는 xargs를 자체의 명령으로 각 라인을 설정하게됩니다. sed -i "s/color/colour/g"명령의 모든 항목을 대체 할 color과를 colour지정한 파일.

경로에 공백이없는 경우에만 작동합니다. 그렇게하면 -0플래그 를 전달하여 널 종료 경로를 xargs에 대한 입력으로 사용해야합니다 . 사용 예는 다음과 같습니다.

$ git ls-files -z "*.tex" | xargs -0 -n 1 sed -i "s/color/colour/g"

위에서 설명한 것과 동일하지만 경로 중 하나에 공백이 있으면 작동합니다.

이것은 find또는 같은 출력으로 파일 이름을 생성하는 모든 명령에서 작동합니다 locate. 파일이 많은 git 저장소에서 사용하면 다음과 같이 git grep -l대신 사용하는 것이 더 효율적일 수 있습니다 git ls-files.

$ git grep -l "color" "*.tex" | xargs -n 1 sed -i "s/color/colour/g"

git grep -l "color" "*.tex"명령은 "color"라는 문구가 포함 된 "* .tex"파일 목록을 제공합니다.


1
사실,하지만 당신이 배운 경우 당신은해야한다 또한 배울 왜 발견의 출력 나쁜 연습을 통해 루핑?
와일드 카드

6

첫 번째 주장은 그 차이를 아주 잘 보여줍니다.

\ls | grep Cases | lessls및에서 생성 한 파일 이름 목록을 찾아 볼 수 있습니다 grep. 파일 이름이 중요하지는 않지만 텍스트 일뿐입니다.

\ls | grep Cases | xargs less명령의 첫 부분에서 이름이 생성 된 파일을 찾아 볼 수 있습니다. xargs입력 및 명령 줄에서 명령으로 파일 이름의 목록을 받아,의 파일 이름으로 명령을 실행 명령 행.

사용을 고려하는 경우 xargs에, 공백으로 구분 : 그것은 이상한 방식으로 서식 입력 기대하는 마음에 계속 \, '그리고 "(때문에 비정상적인 방법으로 인용 부호를 사용 \하지 특수 내부 인용 부호)입니다. xargs파일 이름에 공백이나가 포함되지 않은 경우 에만 사용 하십시오 \'".


@Gilles : 공간 문제를 해결할 수 xargs있는 -0, --null옵션이 있습니다 (나는 당신에게서 그것을 배웠을 가능성이 높습니다 :), 나는 당신이 옵션 없음 xarg전화를 말하는 것으로 가정하지만 인용에 대한 언급에 의지 합니다. 관련 링크 또는 예가 있습니까? . ... (PS | xargs less편리한 "속임수"1 .. 감사합니다 ..입니다
Peter.O

4

귀하의 예에서는 원하는 것을 정확하고 안전하게 수행 할 xargs것이므로 전혀 사용할 필요가 없습니다 find.

정확히 사용하려는 find것은 다음과 같습니다.

find -maxdepth 1 -name '*Cases*' -exec touch {} +

이 예에서는 -maxdepth 1현재 디렉토리에서만 검색하고 하위 디렉토리로 내려 가지 않음을 의미합니다. 기본적으로 find는 maxdepth로 제한하지 않는 한 모든 하위 디렉토리 (주로 원하는 것)를 찾습니다. 는 {}그 자리에 대체하고,이 얻을 것이다 파일의 이름 +이 끝 명령 마커 중 하나, 다른 존재입니다 ;. 차이점은 ;각 파일에서 명령을 한 번에 하나씩 실행 한다는 의미이고 +모든 파일에서 명령을 한 번에 실행한다는 의미입니다. 그러나 셸이 아마도 ;자체 해석을 시도 할 것이므로 \;또는 으로 이스케이프해야합니다 ';'. 예, find이와 같은 작은 성가심이 있지만 그 힘은 그것을 보완하는 것 이상입니다.

모두 find와는 xargs처음에 배울 까다로운 있습니다. 배우기 xargs위해 -p또는 --interactive옵션을 사용하여 실행하려고 하는 명령을 표시하고 실행할 것인지 묻는 메시지를 표시하십시오.

마찬가지로 대신 명령을 실행할지 묻는 메시지 대신 find사용할 수 있습니다 .-ok-exec

그러나 find원하는 모든 작업을 수행 할 수없고 그 위치에 xargs도달 하는 경우 가 있습니다.이 -exec명령은 하나의 {}나타나는 인스턴스 만 허용 하므로 오류가 find -type f -exec cp {} {}.bak \;발생하면 대신 그렇게 할 수 있습니다. :find -type f -print0 | xargs -0 -l1 -IX cp X X.bak

GNU Findutils 매뉴얼 에서 Run Commands 에 대해 더 배울 수 있습니다 .

또한 find파일을 처리 할 때 공백이나 다른 문자가 발생 xargs하기 때문에 대신 null 옵션으로 끝나는 입력 항목을 생성하는 항목과 함께 -0또는 --null옵션 을 사용하지 않으면 문제가 발생할 수 있기 때문에 원하는 것을 안전하게 수행 한다고 언급했습니다. 공백.



@Wildcard 파일 이름은 공백이나 문자가 '있거나 "문제가 될 수 있지만 문제가 find없는 경우를 처리합니다.
aculich

예, 알아요 링크 된 질문에 대한 내 답변을 참조하십시오 . 나는 아마도 그 질문을 위의 주석에있는 진술에 다시 말했거나 그 앞에 "질문을 보아라 ..."라는 문구를 추가했을 것이다. : D
와일드 카드

1

xargs(함께 find, sort, du, uniq, perl및 일부 기타) "STDIN NUL은 (0 × 00) 바이트에 의해 분리 된 파일의리스트를 갖는다」라고하는 명령 줄 스위치를 수용한다. 따라서 공백과 기타 재미있는 문자가 포함 된 파일 이름을 쉽게 처리 할 수 ​​있습니다. 파일 이름에 NUL이 포함되어 있지 않습니다.


2
"파일 이름 null을 포함 할 수 없습니다 ."
amphetamachine
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.