Bash

每行管道輸入執行一次命令?

  • July 19, 2021

我想為ls | grep pattern -. 在這種情況下,我想我可以做到,find pattern -exec java MyProg '{}' \;但我對一般情況很好奇 - 有沒有一種簡單的方法可以說“為每一行標準輸入執行一次命令”?(在魚或 bash 中。)

接受的答案有正確的想法,但關鍵是通過xargs開關-n1,這意味著“每個命令行最多使用 1 個參數”

cat file... | xargs -n1 command

或者,對於單個輸入文件,您可以cat完全避免管道,只需使用:

<file xargs -n1 command

2020 年 8 月 5 日更新:

我還想回應使用者 Jander 評論中的建議,儘管其中包含一些錯誤資訊,我現在將解釋這一點。

不要急於推薦 的-L選項xargs,更不用說其(所謂的)尾隨空白功能可能導致的麻煩。在我看來,這個開關弊大於利,而且對於 的情況來說,這肯定是一種延伸,用於表示-L 1一次只對一條非空行進行操作。公平地說,手冊頁xargs確實說明了開關的特性(即問題) 。-L

由於 Jander 沒有提到這些問題,可能是在-L向可能是匆忙的、毫無戒心的 StackOverflow 觀眾尋求快速提示並且沒有時間閱讀手冊頁等乏味的事情而不是接受評論和答案作為福音時,我現在將提出我的理由-L如果沒有仔細了解它帶來的所有行李,這是一個非常糟糕的建議。

為了說明我對 的鄙視-L,讓我們考慮一個簡單的輸入文件,該文件由某人不小心輸入的以下文本組成(可能是一個高中暑期實習生,創建了這個數據文件作為他/她的培訓的一部分,其Windowish文件名就是證明。作為運氣(業力?)會得到它,您已被管理層選為新的保管人):

testdata.txt

1
2␠
3

由於包含數字的行2有一個空格字元(在前面的程式碼中顯示為數字後的 UnicodeSYMBOL FOR SPACE字形2,以防您的瀏覽器的字型沒有該字元的視覺表示),使用的命令xargs -L1,如:

<testdata.txt xargs -L1 echo

…,將產生以下(也許令人驚訝)輸出:

1
2 3

這是由於-L開關指示xargs後續行附加到以空格結尾的行,這種行為可能只會在那些奇怪的時刻影響結果輸出,其中行沒有正確修剪尾隨空格 - 一個定時炸彈錯誤正在等待正確的輸入文件來展示自己。

另一方面,使用, 而不是-n 1開關的相同命令會產生更可接受的輸出:xargs``-L 1

1
2␠
3

這還不是最糟糕的!-L開關不同於-n強制“可怕的”選項-x生效xargsxargs如果遇到它認為對於執行它的環境來說太長的命令行,這將導致程序終止。

一個由多行連續尾隨空格組成的輸入文件,根據-L開關的指示及其在混合中使用稱為 Agent 的化學試劑,如果將所有這些連接到一個行中超過’ -x,則可能導致xargs中途終止行的定義對於命令行來說太長了。如果事情開始變得模糊,請考慮line is too long是根據為其執行的平台指定的最大長度確定的大小,並進一步偏移一個看似任意的常數,如手冊頁中更詳細說明的那樣. 記住微積分中那些討厭的不定積分及其xargs``xargs任意常數並在測驗或測試中失去一分,因為你忘記+ C在你的解決方案之後寫一個不定積分?-L好吧,如果添加到您方便的工具包中,那句話又回來了,再次咬住您的後背xargs

另一方面,-n值為_是否以空格結尾。不再需要排長隊,也不再需要通過突然終止來刺傷你——Et tu,Brute?1``xargs``xargs -x

關於 xargs 手冊頁中的措辭的可選 segue

我不知道為什麼在整個手冊頁中都使用了模棱兩可和非標準的空白xargs詞,而不是更好地定義和更少模棱兩可的選項,例如:

  • 空格,如果空格表示一個或多個ASCII 空格字元
  • 除換行符以外的空格(如果這是空格所暗示的)
  • 集合中的一個或多個不可列印字元:{空格,水平製表符}(如果將空格用作這個可怕的雙胞胎的同義詞)

2021 年 6 月 15 日更新:

使用者@BjornW 詢問如何使用每xargs輸入執行一次命令而不僅僅是輸入單詞。(看,我確實閱讀了評論,我只會責怪在 Covid 上做出回應的七個月:P)。

本著原始問題的精神,如所問,為了使我的答案適用於更多的案例,我想詳細討論這個特定的場景。

考慮以下輸入文件。它充滿了在Real World ™ 中可能實際遇到的各種邊緣情況(例如,前導/尾隨空格、僅由空格組成的行、空行、以連字元開頭的行

$$ which should not get interpreted as the introduction of a switch $$, 等等。): lines.txt

a1 a22 a333 a4444
b4444 b333 b22 b1
␠␠c d e f g
␣
hhh
ii jj kk␠
␣
␠␠␠
-L and -x are the gruesome twosome
␣
␣
␣

在前面的輸入文件中,Unicode 字元OPEN BOXU+2423 用於標記空行,UnicodeSYMBOL FOR SPACE用於前導和尾隨空格,以使它們更加突出。

假設我們想在輸入的每一行上執行一個命令,作為一個整體,並作為單個參數傳遞給我們的命令,而不考慮內容(包括沒有內容)。我們將使用xargs,如下所示(注意:printf將是我們的範例命令,並且%q格式說明符將用於將提供的參數括在撇號中以清楚起見,當存在空格或參數是空字元串時 - 全部在,只有我們的hhh輸入行“毫髮無損” %q,正如您將在不久的輸出中看到的那樣。如果存在任何不可列印的字元,它們也會通過%q使用 POSIX$''引用語法得到轉義]):

<lines.txt xargs -n1 -d'\n' printf -- 'Input line: %q\n'

輸出如下:

Input line: 'a1 a22 a333 a4444'
Input line: 'b4444 b333 b22 b1'
Input line: '   c d e f g'
Input line: ''
Input line: hhh
Input line: 'ii jj kk '
Input line: ''
Input line: '   '
Input line: '-L and -x are the gruesome twosome'
Input line: ''
Input line: ''
Input line: ''

所以你有它。使用該-d開關,我們可以指定xargs應在輸入文件中查找的分隔符,以指示參數結束的位置和下一個參數的開始位置。通過將其設置為'\n'xargs本身足夠聰明,可以解釋為C 風格的字元轉義-d,如其頁面上開關的描述中所述man,我們可以使用xargs將整行輸入轉發到我們選擇的命令作為參數,並且使用最少我們的努力。

我還想提一下,它xargs可用於連接多行輸入(有一個警告,我將在本段末尾詳細說明),對於需要這種行為的極少數情況,並將它們作為單個參數轉發給我們的命令。這可以通過在上述呼叫命令中將傳遞給-nswitch的數字設置xargs為一個值來完成,該值指示應該合併到單個參數中的輸入行數,並將其\n行尾作為過程的一部分刪除. 不幸的是,這種新行剝離行為使得上述xargs方法不適用於許多案例,因為指示一行結束和下一行開始的資訊會在此過程中失去。

在 Bash 或任何其他 Bourne 樣式的 shell(ash、ksh、zsh、…)中:

while read -r line; do command "$line"; done

read -r從標準輸入中讀取一行(read-r解釋反斜杠,你不想要那個)。因此,您可以執行以下任一操作:

$ command | while read -r line; do command "$line"; done  

$ while read -r line; do command "$line"; done <file

引用自:https://unix.stackexchange.com/questions/7558