Xargs가 파이프라인의 두 번째 측면에 들어가나요?

Xargs가 파이프라인의 두 번째 측면에 들어가나요?

나는 다음을 수행하려고합니다 :

cat file1.txt | xargs -I{} "cat file2.txt | grep {}"

file1의 각 줄은 세 번째 파이프 끝의 grep 값이 될 것으로 예상합니다. 예상대로 작동하지 않습니다.

-I{}파이프라인에 도달하면 대체품 찾기를 중단하기 때문입니까 ? 해결책이 있나요?

답변1

파이프를 생성하거나 리디렉션을 수행하려면 셸이 필요하기 때문입니다. 이는 cat연결 명령이므로 하나의 파일에만 사용하는 것은 거의 의미가 없습니다.

cat file1.txt | xargs -I{} sh -c 'cat file2.txt | grep -e "$1"' sh {}

하다아니요하다:

cat file1.txt | xargs -I{} sh -c 'cat file2.txt |

이는 명령 주입 취약점과 동일하기 때문입니다. {}code 매개변수의 sh쉘 코드로 확장 됩니다 . 예를 들어, 행이 이면 file1.txt호출 $(reboot)됩니다 reboot.

( -e또는 --)도 중요합니다. 이것이 없으면 로 시작하는 정규식에 문제가 있습니다 -.

대신 리디렉션을 사용하여 위의 내용을 단순화할 수 있습니다 cat.

< file1.txt xargs -I{} sh -c '< file2.txt grep -e "$1"' sh {}

또는 리디렉션을 사용하는 대신 파일 이름을 인수로 전달하면 됩니다 grep. 이 경우 다음을 제거할 수도 있습니다 sh.

< file1.txt xargs -I{} grep -e {} file2.txt

grep한 번의 호출로 모든 정규식을 찾을 수도 있습니다 .

grep -f file1.txt file2.txt

하지만 이 경우에는 한 줄에 하나의 정규식만 있고 file1.txt특별한 인용은 수행되지 않습니다 xargs.

xargs기본적으로 입력은 빈 목록(일부 구현에서는 공백과 탭만, 다른 구현에서는 [:blank:]현재 로케일의 문자 클래스에 있는 모든 문자) 또는 백슬래시 대시와 작은따옴표 및 큰따옴표가 포함된 개행으로 구분된 단어로 처리됩니다. 구분 기호(개행은 백슬래시로만 이스케이프할 수 있음) 또는 서로를 이스케이프하는 데 사용됩니다.

예를 들어 다음과 같은 입력의 경우:

 'a "b'\" "bar baz" x\
y

xargs아무것도 -I{}전달되지 a "b"않고 주문 bar baz됩니다 x<newline>y.

를 사용하면 -I{}xargs줄에 한 단어가 얻어지지만 일부 추가 처리가 계속 수행됩니다. 선행(후행은 아님) 공백은 무시합니다. 공백은 더 이상 구분 기호로 간주되지 않지만 견적 처리는 계속 진행 중입니다.

위 입력은 xargs -I{}명령에 인수를 전달합니다. a "b" foo bar x<newline>y또한 POSIX 요구 사항으로 인해 단어 길이가 255자를 초과하면 많은 시스템이 작동하지 않습니다. 대체로 xargs -I{}꽤 쓸모가 없습니다.

각 줄을 명령의 인수로 그대로 전달하려면 GNU xargs -d '\n'확장을 사용할 수 있습니다.

< file1.txt xargs -d '\n' -n 1 grep file2.txt -e

(이것은 grep옵션이 인수 뒤에 전달되거나(POSIX적으로 올바른 옵션이 환경에 존재하지 않는 경우) 이식 가능하도록 허용하는 GNU의 또 다른 확장에 의존합니다.

sed "s/'/'\\\\\\''/g;s/.*/'&'/" file1.txt | xargs -n1 sh -c '
  for line do
    grep -e "$line" file2.txt
  done' sh

당신이 원한다면 모든단어각각 대신 에 file1.txt(따옴표는 여전히 인식됩니다)철사찾으려면(한 줄에 단어가 하나만 있고 후행 공백 문제도 해결되는 경우) 다음 xargs -n1대신 단독으로 사용할 수 있습니다 -I.

< file1.txt xargs -n1 sh -c '
  for word do
    grep -e "$word" file2.txt
  done' sh

선행 및 후행 공백을 제거하려면(따옴표 처리 없이 xargs) 다음을 수행할 수도 있습니다.

unset IFS # restore word splitting to its default
while read -r regexp; do
  grep -e "$regexp" file2.txt
done < file1.txt

답변2

수행하려는 작업에 따라 xargs완전히 건너뛰고 다음 솔루션을 사용하는 것이 더 나을 수도 있습니다.

grep -f file1.txt file2.txt

이것은 원래 명령과 다릅니다(Stéphane Chazelas의 답변에 따라 수정하면) 다음과 같습니다.

  • file2.txt일치하는 패턴에 관계없이 나타나는 순서대로 줄이 인쇄됩니다 . 명령에서 첫 번째 패턴과 일치하는 모든 줄이 인쇄된 다음 두 번째 패턴과 일치하는 모든 줄이 인쇄됩니다.
  • 여러 패턴과 일치하는 라인은 한 번만 인쇄됩니다. 명령에서는 일치하는 각 패턴에 대해 한 번씩 인쇄됩니다.
  • -v및를 포함한 여러 플래그를 더 쉽게 사용할 수 있습니다 -c.

깃발 -fPOSIX에 의해 지정됨그러므로 휴대성이 매우 좋습니다.

관련 정보