
나는 다음을 수행하려고합니다 :
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 {}
하다~ 아니다하다:
고양이 파일1.txt | xargs -I{} sh -c 'cat file2.txt | grep -e {}'
이는 명령 주입 취약점에 해당합니다. {}
코드 인수에서 확장되어 쉘 sh
코드로 해석됩니다. 예를 들어, 라인 중 하나가 file1.txt
was $(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{}
pass 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
(여기서는 인수 뒤에 옵션을 전달할 수 있는 GNU의 또 다른 확장에 의존합니다 grep
(POSIX가 올바른 환경에 없는 경우) 또는 이식 가능:
sed "s/'/'\\\\\\''/g;s/.*/'&'/" file1.txt | xargs -n1 sh -c '
for line do
grep -e "$line" file2.txt
done' sh
각각 원하셨다면단어in 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에 의해 지정됨따라서 합리적으로 휴대 가능합니다.