如何循環 STDIN 中的行並執行 shell 命令?

如何循環 STDIN 中的行並執行 shell 命令?

我想在從 STDIN 取得的每一行上執行 shell 命令。

在這種情況下,我想跑步xargs mv。例如,給定兩行:

mfoo foo
mbar bar

我想運行:

xargs mv mfoo foo
xargs mv mbar bar

我已經嘗試了以下策略rubyawk、 和xargs。然而,我做錯了:

只是xargs

$ echo "mbar bar\nmbaz baz" | xargs mv
usage: mv [-f | -i | -n] [-v] source target
       mv [-f | -i | -n] [-v] source ... directory

通過awk

$ echo "mbar bar\nmbaz baz" | awk '{ system("xargs $0") }'

通過ruby

$ echo "mbar bar\nmbaz baz" | ruby -ne '`xargs mv`'
$ ls
cat  foo  mbar mbaz

我有一些疑問:

  • 我該如何做我想做的事?
  • 我的每一次嘗試都出了什麼問題?
  • 有沒有更好的方法來「思考」我正在嘗試做的事情?

我特別困惑的是我的xargs嘗試不起作用,因為以下方法有效:

$ echo "foo\nbar" | xargs touch
$ ls
bar foo

答案1

echo "mbar bar\nmbaz baz" | xargs mv

xargs應該使用該-t選項來看看發生了什麼。因此,在上面的情況下,如果我們要呼叫xargswith -t,我們會看到什麼:

mv mbar bar mbaz baz

所以顯然這是不正確的。發生的事情是,xargs就像一條飢餓的鱷魚,吃掉了透過管道餵給它的所有參數echo。所以你需要一種方法來限制向 croc 釋放參數。由於您是按行請求的,因此您需要的是-l-Lfor POSIX 選項。

echo "mbar bar\nmbaz baz" | xargs -l -t mv

POSIX 方式:

echo "mbar bar\nmbaz baz" | xargs -L 1 -t mv

mv mbar bar
mv mbaz baz

這就是你想要的。華泰

答案2

你可以這樣走:

echo -e "foo bar\ndoo dar" | xargs -n 2 mv

從文件中讀取:

cat lines.txt | xargs -n 2 mv

或者

xargs -a lines.txt -n 2 mv

答案3

xargs可能不會按照您的預期行事。請參閱@MichaelHomer對此問題的評論:

xargs mv mfoo foo將等待輸入並為它獲得的mfoo foo $x_1 $x_2 $x_3...每一行輸入運行 mv 。 $x_n@邁克爾霍默

這可以透過閱讀來確認xargs手冊頁

描述
xargs 實用程式從標準輸入讀取空格、製表符、換行符和檔案結尾分隔的字串,並使用這些字串作為參數執行實用程式。

xargs在實踐中,當將參數提供給作為第一個參數給出的命令列實用程式時,似乎會忽略換行符。例如,請注意換行符會發生什麼:

$ echo "foo bar\ncat dog"
foo bar
cat dog
$ echo "foo bar\ncat dog" | xargs echo
foo bar cat dog

這種行為可以透過以下方式控制-n旗幟

-n 數字


設定每次呼叫實用程式時從標準輸入取得的參數的最大數量。

回到前面的例子,如果我們只想xargs使用 2 個參數然後退出,那麼我們可以使用@ddnomad 的方法

$ echo "foo bar\ncat dog" | xargs -n 2 echo
foo bar
cat dog

另外,如 Rakesh Sharma 的答案中的評論所示,在 BSD 上,xargs您可以使用標誌指定要讀取的行數-L。從手冊頁:

-L號

為每個讀取的數軸呼叫實用程式。如果達到 EOF 並且
讀取的行數少於數量,則將使用可用行呼叫實用程式。

測試同樣有幫助的是-t開關:

重新審視我們的範例,以下兩種方法都可以工作;然而,第二個例子更好,因為這正是本例的目的:

$ echo "foo bar\ncat dog" | xargs -n 2 echo
foo bar
cat dog
$ echo "foo bar\ncat dog" | xargs -L 1 echo
foo bar
cat dog

手冊頁中的註釋:

-L 和 -n 選項是互斥的;將使用最後給出的一個。

答案4

有一個非常簡單的解決方案,不使用 xargs。
定義這個函數:

$ mv2() { while (($# >1 )); do echo mv "$1" "$2"; shift 2; done; }

然後,只需使用所需的檔案名稱列表來呼叫它(不需要換行符號):

$ mv2 mbar bar mbaz baz
mv mbar bar
mv mbaz baz

去掉迴聲,使功能真正發揮作用。

相關內容