Xargs 進入管線的第二側?

Xargs 進入管線的第二側?

我正在嘗試執行以下操作:

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

我期望 file1 中的每一行都是第三個管道末端的 grep 的值。它沒有按預期工作。

這是因為-I{}一旦它到達管道就停止尋找替換的東西嗎?有沒有解決的辦法?

答案1

這是因為您需要一個 shell 來建立管道或執行重新導向。請注意,這cat是連接命令,僅對一個檔案使用它沒有什麼意義。

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

不是做:

貓檔1.txt | xargs -I{} sh -c 'cat file2.txt | xargs -I{} sh -c 'cat file2.txt | xargs -I{} sh -c 'cat file2.txt | grep -e {}'

因為這相當於命令注入漏洞。將{}在程式碼參數中擴展sh為 shell 程式碼。例如,如果 的 一行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 bazx<newline>y命令。

使用 時-I{}xargs每行獲取一個單詞,但仍進行一些額外的處理。它忽略前導(但不忽略尾隨)空格。空格不再被視為分隔符,但報價處理仍在進行中。

上面的輸入將向命令xargs -I{}傳遞一個參數。a "b" foo bar x<newline>y另請注意,根據 POSIX 的要求,如果單字長度超過 255 個字符,許多系統將無法運作。總而言之,xargs -I{}很沒用。

如果您希望將每一行逐字作為參數傳遞給命令,您可以使用 GNUxargs -d '\n'擴充:

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

(這裡依賴 GNU 的另一個擴展grep,它允許在參數之後傳遞選項(前提是環境中不存在 POSIXly 正確的選項)或可移植:

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 指定因此相當便攜。

相關內容