“xargs grep”은 무엇을합니까?


25

내가 알고 grep명령을 난의 기능에 대해 배우고 xargs내가 읽어 때문에, 사용하는 방법에 대한 몇 가지 예를 제공 페이지 xargs명령을 사용합니다.

마지막 예제 인 예제 10과 혼동됩니다. "xargs 명령은 grep 명령을 실행하여 문자열 'stdlib.h'를 포함하는 모든 파일 (find 명령이 제공 한 파일 중)을 찾습니다"라고 말합니다.

$ find . -name '*.c' | xargs grep 'stdlib.h'
./tgsthreads.c:#include
./valgrind.c:#include
./direntry.c:#include
./xvirus.c:#include
./temp.c:#include
...
...
...

그러나 단순히 사용하는 것의 차이점은 무엇입니까?

$ find . -name '*.c' | grep 'stdlib.h'

?

분명히, 나는 여전히 정확히 xargs 가하는 일로 어려움을 겪고 있으므로 도움을 주시면 감사하겠습니다!


2
이 질문이 도움이 될 수 있습니다. XArgs는 언제 필요합니까?
TheOdd

답변:


30
$ find . -name '*.c' | grep 'stdlib.h'

이렇게하면 출력 (stdout) *에서 find~까지 (stdin of) * grep 'stdlib.h' 가 텍스트로 파이프 됩니다 (즉, 파일 이름은 텍스트로 처리됨). grep일반적인 일을 하고이 텍스트 (패턴 자체를 포함하는 파일 이름)에서 일치하는 줄을 찾습니다. 파일의 내용은 읽지 않습니다.

$ find . -name '*.c' | xargs grep 'stdlib.h'

이것은 구축 명령 grep 'stdlib.h' 에서 각 결과가되는 find인수가 -이 경기를 찾습니다 있도록 내부에 각 파일이 발견 find( xargs주어진 명령에 인수로 자사의 표준 입력을 켜기로 생각 될 수 있습니다) *

-type ffind 명령에 사용 하지 않으면 grep일치하는 디렉토리 에서 오류가 발생합니다 . 파일명은 공백이 경우에도, xargs그렇게 추가하여 널 분리기를 사용 심하게 망치지 것 -print0xargs -0보다 안정적인 결과 :

find . -type f -name '*.c' -print0 | xargs -0 grep 'stdlib.h'

* @cat의 의견에서 제안한 바와 같이 추가 설명 포인트를 추가했습니다.


2
grep의 인수와 같지 않고 grep의 stdin에| 파이프 stdout 을 파이프 하고 혼란스러운 결과를 제공 하는 핵심 포인트를 언급하는 것이 좋습니다 (생략하지 않은 것처럼 보이기) .
cat

1
또는 GNU find를 사용하십시오 find -name '*.c' -exec grep stdlib.h {} +. 나는 실제로 xargs를 거의 사용하지 않습니다. 또한 xargs가 grep $(find)명령 대체 와 비슷한 목적으로 사용된다고 언급 한 사람은 아무도 없습니다 . xargs를 더 적은 제한과 문제로 명령 대체로 설명하는 것은 자연스러운 것 같습니다.
Peter Cordes

xargs를 사용하는 한 가지 상황은 찾기 결과 많은 파일을 삭제하는 경우입니다. -exec rm 만 수행하면 한 번에 하나씩 각 파일에서 rm을 실행하므로 매우 비효율적입니다. xargs로 파이프하면 하나의 rm으로 한 번에 모두 수행됩니다. say -n50 (한 번에 50 개)으로 제한하면 명령 줄 오버플로를 방지 할 수 있습니다 (많은 파일에 문제가 있음).
lsd

1
@lsd : 왜 find -delete특별한 경우에 적합하지 않습니까? 또는 rmGNU find를 사용하는 경우 이외의 명령의 경우 -exec some_command {} +xargs와 같은 배치 로 그룹화하는 대신 \;명령을 개별적으로 실행하는 동작이 있습니다.
Peter Cordes

@lsd find이 사용하고 경우만 실행 각 파일에 명령 -exec command \;모두를 xargs하고 -exec command \+시스템에 의해 허용되는 인수의 최대 수와 명령을 호출합니다. 다시 말해, 그들은 동등합니다
Sergiy Kolodyazhnyy

6

xargs는 표준 입력을 가져 와서 명령 행 인수로 바꿉니다.

find . -name '*.c' | xargs grep 'stdlib.h' 매우 유사하다

grep 'stdlib.h' $(find . -name '*.c')  # UNSAFE, DON'T USE

파일 이름 목록이 단일 명령 줄에 비해 너무 길지 않은 한 동일한 결과를 제공합니다. (Linux는 단일 명령 행에서 메가 바이트의 텍스트를 지원하므로 일반적으로 xargs가 필요하지 않습니다.)


그러나 파일 이름에 공백이 있으면 깨지기 때문에 둘 다 빨라 집니다. 대신 find -print0 | xargs -0작동하지만 작동합니다.

find . -name '*.c' -exec grep 'stdlib.h' {} +

파일 이름을 어디서나 파이프하지 않습니다 find. 큰 명령 줄에 배치하고 grep직접 실행 합니다.

\;+각 파일마다 grep을 별도로 실행하는 대신 훨씬 느립니다. 하지마 그러나 +GNU 확장이므로 xargsGNU find를 가정 할 수 없으면 효율적으로 수행 해야 합니다.


당신이 밖으로두면 xargs, find | grep그 파일 이름의 목록과 그 패턴 매칭을 수행 find인쇄합니다.

따라서 그 시점에서 그냥 할 수도 있습니다 find -name stdlib.h. 물론을 사용 -name '*.c' -name stdlib.h하면 이러한 패턴이 모두 일치 할 수 없으므로 find의 기본 동작은 규칙을 AND로하는 것이므로 출력을 얻지 못합니다.

less프로세스의 어느 시점에서나 대체 하여 파이프 라인의 어떤 부분에서 어떤 출력이 생성되는지 확인하십시오.


더 읽을 거리 : http://mywiki.wooledge.org/BashFAQ 에는 훌륭한 것들이 있습니다.


1
GNU xargs는 또한 -d구분 기호를 설정해야하므로 -d'\n'줄 바꿈으로 구분 된 목록을 처리하는 데 사용할 수 있습니다. 파일 이름이없는 한 파일 등의 파일 이름 목록을 처리하는 경우 유용 할 수 있습니다 그들에 개행, 즉.)
ilkkachu

@ilkkachu : 예, 파일 이름의 줄 바꿈은 대부분의 스크립트를 손상시키기 때문에 공백보다 훨씬 드 most니다. myfunc(){ local IFS=$'\n'; fgrep stdlib.h` $ (find) ; }도 같은 효과로 작동합니다. 또는 단일 라이너로서 (IFS=...; cmd...)서브 쉘은 IFS에 대한 변경 사항을 저장 / 복원하지 않고 포함하도록 작동합니다.
Peter Cordes

@PeterCordes 제발 command $( find )종류의 물건을 하지 마십시오 . 공백과 특수 문자가 포함 된 문제가있는 파일 이름은 이러한 유형의 파일을 손상시킬 수 있습니다. 최소한 큰 따옴표는 명령 대체입니다.
Sergiy Kolodyazhnyy

@ SergiyKolodyazhnyy : 실제로 그렇게하는 것이 좋습니다. 사람들은 다음 섹션을 읽는 대신 복사 / 붙여 넣기를했을 수도 있습니다. 이를 해결하기 위해 업데이트되었습니다.
Peter Cordes

@ SergiyKolodyazhnyy : 또는 당신은 나의 코멘트에 응답하고 있었습니까? IFS을 사용하는 것과 동일하게 설정 했습니다 xargs '-d\n'. 나는 그것도 포함 된 파일 이름으로 안전하다고 생각하므로 글로브 확장 및 쉘 메타 문자 처리, 명령 치환의 효과 이전에 발생 $()또는 >. 파일 이름에 대해 알고있는 일회성 대화식 사용을 제외하고 명령 대체에서 단어 분할을 사용하는 것은 좋지 않습니다. 그러나 command "$(find)"정확히 1 개의 파일 이름을 생성 할 것으로 예상되는 경우에만 유용합니다.
Peter Cordes

5

일반적으로, 한 명령에서 다른 명령으로 xargs기호를 사용하여 () 기호를 파이프 하지만 첫 번째 명령의 출력이 두 번째 명령의 입력으로 올바르게 수신되지 않는 경우에 사용됩니다.|Command1 | Command2

이는 일반적으로 두 번째 명령이 표준 입력 (stdin)을 통해 입력 된 데이터를 올바르게 처리하지 않는 경우에 발생합니다 (예 : 입력으로 여러 줄, 입력 방법, 입력으로 사용 된 문자, 입력으로 여러 매개 변수, 수신 된 데이터 유형 입력 등). 간단한 예제를 제공하려면 다음을 테스트하십시오.

예 1 :

ls | echo- echo그가받는 입력을 처리하는 방법을 모르기 때문에 아무 것도 하지 않습니다. 이제이 경우에 우리가 xargs그것을 사용 한다면 echo(예를 들어 : 한 줄의 정보로) 올바르게 처리 할 수있는 방식으로 입력을 처리 할 것 입니다

ls | xargs echo-모든 정보를 ls한 줄에 출력합니다.

예 2 :

go라는 폴더 안에 여러 개의 goLang 파일이 있다고 가정 해 봅시다. 나는 이런 식으로 그들을 찾을 것입니다 :

find go -name *.go -type f | echo-그러나 파이프 기호가 있고 echo끝에 있으면 작동하지 않습니다.

find go -name *.go -type f | xargs echo-덕분에 작동 xargs하지만 find명령의 각 응답을 한 줄로 원하면 다음을 수행하십시오.

find go -name *.go -type f | xargs -0 echo-이 경우의 동일한 출력 find이로 표시됩니다 echo.

와 같은 명령 cp, echo, rm, less을 사용하면 입력을 처리하는 더 나은 방법이 필요한 다른 명령을 사용할 수 있습니다 xargs.


4

xargs 파일 목록을 기반으로 명령 줄 인수를 자동 생성하는 데 사용됩니다.

따라서 followoing xargs명령 을 사용하는 몇 가지 대안을 고려하십시오 .

find . -name '*.c' -print0 | xargs -0 grep 'stdlib.h'

다른 답변에서 처음 언급되지 않은 다른 옵션 대신에 몇 가지 이유가 있습니다.

  1. find . -name '*.c' -exec grep 'stdlib.h' {}\;grep모든 파일에 대해 하나의 프로세스를 생성 합니다. 이는 일반적으로 나쁜 습관으로 간주되며 많은 파일이 발견되면 시스템에 큰 부하를 줄 수 있습니다.
  2. 파일 grep 'stdlib.h' $(find . -name '*.c')이 많으면 $(...)작업 의 출력 이 셸의 최대 명령 줄 길이를 초과 하므로 명령이 실패 할 수 있습니다.

다른 답변에서 언급 했듯이이 시나리오에서 -print0인수를 사용하고 xargs find에 인수를 사용하는 이유 -0는 특정 문자 (예 : 따옴표, 공백 또는 줄 바꿈)가있는 파일 이름이 여전히 올바르게 처리되기 때문입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.