[xargs] xargs가 각 입력 줄에 대해 명령을 한 번 실행하도록하십시오.

xargs가 주어진 각 입력 행에 대해 정확히 한 번만 명령을 실행하도록하려면 어떻게해야합니까? 기본적으로 행을 청크하고 명령을 한 번 실행하여 각 인스턴스에 여러 행을 전달하는 것이 기본 동작입니다.

에서 http://en.wikipedia.org/wiki/Xargs :

찾기 / 경로-타입 f -print0 | xargs -0 rm

이 예제에서 find는 긴 파일 이름 목록으로 xargs의 입력을 공급합니다. 그런 다음 xargs는이 목록을 하위 목록으로 나누고 모든 하위 목록에 대해 rm을 한 번 호출합니다. 이것은 기능적으로 동등한 버전보다 효율적입니다.

/ path -type f -exec rm ‘{}’찾기 \;

find에 “exec”플래그가 있음을 알고 있습니다. 다른 리소스의 예제를 인용하고 있습니다.



답변

입력에 공백이없는 경우에만 다음이 작동합니다.

xargs -L 1
xargs --max-lines=1 # synonym for the -L option

매뉴얼 페이지에서 :

-L max-lines
          Use at most max-lines nonblank input lines per command line.
          Trailing blanks cause an input line to be logically continued  on
          the next input line.  Implies -x.


답변

이 페이지의 모든 기존 답변이 올바른 것으로 표시된 답변을 포함하여 잘못된 것 같습니다. 그것은 질문이 모호하게 표현되어 있다는 사실에서 비롯됩니다.

요약 :   명령을 “한 줄씩 입력 할 때마다 정확히 한 번” 명령을 실행하려면 전체 행 (줄 바꿈없이)을 단일 인수 로 명령에 전달 하면 가장 적합한 UNIX 호환 방법입니다.

... | tr '\n' '\0' | xargs -0 -n1 ...

GNU xargs는 유용한 확장 기능을 가지고 있거나 가지고 있지 않을 수도 tr있지만 OS X 및 기타 UNIX 시스템에서는 사용할 수 없습니다.

이제 긴 설명을 위해…


xargs를 사용할 때 고려해야 할 두 가지 문제가 있습니다.

  1. 입력을 “인수”로 어떻게 분할합니까? 과
  2. 한 번에 자식 명령을 전달할 인수 수

xargs의 동작을 테스트하려면 실행 횟수와 인수 수를 보여주는 유틸리티가 필요합니다. 표준 유틸리티가 있는지 모르겠지만 bash에서 쉽게 코딩 할 수 있습니다.

#!/bin/bash
echo -n "-> "; for a in "$@"; do echo -n "\"$a\" "; done; echo

show현재 디렉토리에 파일 을 저장하고 실행 가능 하다고 가정하면 다음과 같이 작동합니다.

$ ./show one two 'three and four'
-> "one" "two" "three and four"

이제 원래의 질문이 실제로 포인트 2에 관한 것이라면 (제 생각에 몇 번 이상 읽은 후) 다음과 같이 읽습니다 (굵게 변경).

주어진 입력 인수 마다 xargs가 명령을 정확히 한 번만 실행하도록하려면 어떻게 해야합니까? 기본 동작은 입력을 인수 로 청크하고 가능한 한 적은 수의 명령 실행하여 각 인스턴스에 여러 인수 를 전달하는 것 입니다.

대답은 -n 1입니다.

xargs의 기본 동작을 비교하여 입력을 공백으로 나누고 명령을 가능한 한 적게 호출합니다.

$ echo one two 'three and four' | xargs ./show
-> "one" "two" "three" "and" "four"

그리고 그것의 행동 -n 1:

$ echo one two 'three and four' | xargs -n 1 ./show
-> "one"
-> "two"
-> "three"
-> "and"
-> "four"

반면에 원래의 질문이 포인트 1에 관한 것이었고 입력 분할과 같이 읽히는 경우 (여기에 오는 많은 사람들이 그런 경우라고 생각하거나 두 가지 문제를 혼란스럽게합니다) :

xargs가 주어진 각 입력 행에 대해 정확히 하나의 인수 로 명령 실행하도록하려면 어떻게 해야합니까? 기본 동작은 공백 주위 의 행을 청크하는 것 입니다.

대답은 더 미묘합니다.

-L 1도움이 될 수 있다고 생각 하지만 인수 구문 분석을 변경하지는 않습니다. 각 입력 행에 대해 한 번만 명령을 실행하며 해당 입력 행에있는 수만큼의 인수를 사용합니다.

$ echo $'one\ntwo\nthree and four' | xargs -L 1 ./show
-> "one"
-> "two"
-> "three" "and" "four"

뿐만 아니라 줄이 공백으로 끝나면 다음 줄에 추가됩니다.

$ echo $'one \ntwo\nthree and four' | xargs -L 1 ./show
-> "one" "two"
-> "three" "and" "four"

분명히, -L에 대한 방법 xargs를 변경하지 않는 것은 인수로 입력을 분할합니다.

크로스 플랫폼 방식 (GNU 확장명 제외)으로 그렇게하는 유일한 인수 -0는 입력을 NUL 바이트로 분할하는 것입니다.

그런 다음 도움을 받아 줄 바꿈을 NUL로 변환하는 것입니다 tr.

$ echo $'one \ntwo\nthree and four' | tr '\n' '\0' | xargs -0 ./show
-> "one " "two" "three and four"

이제 인수 구문 분석은 후행 공백을 포함하여 올바르게 보입니다.

마지막 으로이 기술을와 결합하면 -n 1입력 줄마다 정확히 하나의 명령 실행이 발생합니다. 입력에 관계없이 원래 질문을 볼 수있는 또 다른 방법 일 수 있습니다 (제목이 주어지면 가장 직관적 일 수 있습니다).

$ echo $'one \ntwo\nthree and four' | tr '\n' '\0' | xargs -0 -n1 ./show
-> "one "
-> "two"
-> "three and four"


답변

에서 나오는 모든 줄 (예 : 결과)에 대해 명령을 실행하려면 find무엇을 xargs위해 필요한가?

시험:

find 당신의 명령을 경로-type f -exec {} \;

여기서 리터럴 {}은 파일 이름으로 대체되고 리터럴 \;find사용자 정의 명령이 종료됨을 알기 위해 필요합니다 .

편집하다:

(질문을 편집 한 후에 대해 알고 있음을 -exec나타냄)

보낸 사람 man xargs:

-L max-lines 명령 행당 최대 max-lines 비 공백 입력 라인을
사용하십시오 . 후행 공백은 입력 라인이 다음 입력 라인에서 논리적으로 계속되도록합니다. -x를 의미합니다.

공백으로 끝나는 파일 이름은 다음을 사용하면 문제를 일으킬 수 있습니다 xargs.

$ mkdir /tmp/bax; cd /tmp/bax
$ touch a\  b c\  c
$ find . -type f -print | xargs -L1 wc -l
0 ./c
0 ./c
0 total
0 ./b
wc: ./a: No such file or directory

당신이 걱정하지 않도록 경우 -exec옵션, 당신은 더 나은 사용 -print0-0:

$ find . -type f -print0 | xargs -0L1 wc -l
0 ./c
0 ./c
0 ./b
0 ./a


답변

xargs가 주어진 각 입력 행에 대해 정확히 한 번만 명령을 실행하도록하려면 어떻게해야합니까?

-L 1간단한 해결책이지만 파일 중 하나에 공백이 있으면 작동하지 않습니다. 이것은 -print0공백 대신 ‘\ 0’문자로 인수를 구분하는 find 인수 의 핵심 기능입니다 . 예를 들면 다음과 같습니다.

echo "file with space.txt" | xargs -L 1 ls
ls: file: No such file or directory
ls: with: No such file or directory
ls: space.txt: No such file or directory

더 나은 해결책은 tr개행을 null ( \0) 문자 로 변환 한 다음 xargs -0인수 를 사용하는 것 입니다. 예를 들면 다음과 같습니다.

echo "file with space.txt" | tr '\n' '\0' | xargs -0 ls
file with space.txt

그런 다음 호출 수를 제한해야하는 경우 -n 1인수를 사용하여 각 입력에 대해 프로그램을 한 번 호출 할 수 있습니다 .

echo "file with space.txt" | tr '\n' '\0' | xargs -0 -n 1 ls

또한 나누기를 널로 변환 하기 전에 find의 출력을 필터링 할 수 있습니다 .

find . -name \*.xml | grep -v /target/ | tr '\n' '\0' | xargs -0 tar -cf xml.tar


답변

다른 대안 …

find /path -type f | while read ln; do echo "processing $ln"; done


답변

이 두 가지 방법도 작동하며 find를 사용하지 않는 다른 명령에서도 작동합니다!

xargs -I '{}' rm '{}'
xargs -i rm '{}'

사용 사례 예 :

find . -name "*.pyc" | xargs -i rm '{}'

pyc 파일에 공백이 있어도이 디렉토리 아래의 모든 pyc 파일이 삭제됩니다.


답변

find path -type f | xargs -L1 command

당신이 필요한 전부입니다.


댓글 달기

이메일 주소를 발행하지 않을 것입니다. 필수 항목은 *(으)로 표시합니다