網頁

2013年3月26日

xargs 將上一個程式輸出當成下一個程式的參數輸入

Origin: xargs 應用介紹

今天介紹的指令是 xargs,這個指令並不常見,卻很實用它的工作是將上一個程式輸出的結果轉成下一個程式的參數輸入

範例:
假設有一個目錄如下 (這個樹狀目錄架構是使用 tree 指令所產生的)

.
|-- Makefile
|-- VERSION
|-- VERSION.bak
|-- inc
|   |-- fork.h
|   |-- main.h
|   `-- main.h.bak
`-- src
    |-- common_lib
    |   |-- dl_math.c
    |   |-- dl_math.c.bak
    |   |-- dl_string.c
    |   `-- dl_string.c.bak
    |-- fork.c
    |-- fork.c.bak
    `-- main.c

這是一個程式開發的專案目錄,如果我想要將所有的*.bak 一次清除,那麼該怎麼做呢? 首先我得先找出所有的 *.bak,可以使用 find 指令

find . -iname "*.bak"

可以得到以下的結果
./VERSION.bak
./inc/main.h.bak
./src/fork.c.bak
./src/common_lib/dl_string.c.bak
./src/common_lib/dl_math.c.bak

接下來就是關鍵了
你會怎麼做呢?
1) 把結果使用">" 導向檔案,全部加入 rm (linux 的刪檔指令)嗎?
2) 還是把這些輸出內容變成 rm 的輸入呢?
第一種方式是愚公移山…如果有幾千個檔案…可能會很辛苦~
第二種方式就是使用xargs 來實現我們的理想

find . -iname "*.bak" | xargs rm

紅色部份就是xargs 使用的方式,它會將前面的輸出轉化為它後方指令的參數輸入
執行之後,所有的*.bak 備份檔都被清乾淨了,所有子目錄下的 bak檔也被清除了
很不錯吧
但是這個寫法還有一點缺失…
就是當前方程式沒有任何輸出時…後方的指令就會沒有參數輸入…
以這個例子來看…就會出現這個錯誤訊息
rm: missing operand
Try `rm --help' for more information.

在xargs 裡面有一個參數是 --no-run-if-empty 可以改善上述的問題,當沒前面的程式沒有輸出時,就不執行後面的程式

find . -iname "*.bak" | xargs --no-run-if-empty rm

上述的指令會有如下的效果:
rm ./VERSION.bak ./inc/main.h.bak ./src/fork.c.bak ./src/common_lib/dl_string.c.bak ./src/common_lib/dl_math.c.bak

有朋友在問,他想要把過濾出來的檔案copy 或mv 到他指定的目錄,會有錯誤訊息
是滴…因為cp 與mv 能接受的參數形態與rm 不一樣
在 rm 之後的參數都會是要刪掉的,而以cp 為例,有二個必要參數就是來源與目的
依照下列範例就行了~

find -iname "*.bak" | xargs -i cp {} ~/bakdir

使用 -i 和 {} 就可以把前面所得到的輸出列表,不是一整串,而是一個一個地傳給後面的指令,上述的指令的效果就像是這樣:
cp ./VERSION.bak ~/bakdir
cp ./inc/main.h.bak ~/bakdir
cp ./src/fork.c.bak ~/bakdir
cp ./src/common_lib/dl_string.c.bak ~/bakdir
cp ./src/common_lib/dl_math.c.bak ~/bakdir

沒有留言:

張貼留言