나는 다음을 수행하려고합니다 :
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
.
깃발 -f
은POSIX에 의해 지정됨그러므로 휴대성이 매우 좋습니다.