我想在從 STDIN 取得的每一行上執行 shell 命令。
在這種情況下,我想跑步xargs mv
。例如,給定兩行:
mfoo foo
mbar bar
我想運行:
xargs mv mfoo foo
xargs mv mbar bar
我已經嘗試了以下策略ruby
、awk
、 和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
選項來看看發生了什麼。因此,在上面的情況下,如果我們要呼叫xargs
with -t
,我們會看到什麼:
mv mbar bar mbaz baz
所以顯然這是不正確的。發生的事情是,xargs
就像一條飢餓的鱷魚,吃掉了透過管道餵給它的所有參數echo
。所以你需要一種方法來限制向 croc 釋放參數。由於您是按行請求的,因此您需要的是-l
或-L
for 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
去掉迴聲,使功能真正發揮作用。