2014年12月12日 星期五

linux, bash, find 的應用(-exec, sed -i, 檔案內取代, 與xargs比較)

find -exec

find -exec 指的是將找到的檔案,送到後面的指令去處理。從-exec\;為止,代表是接受從find送來要處理的指令,而送來的檔案將用{}代表找到的檔案。

譬如你想把所有副檔名為.log的檔案刪除掉,可以這麼做

find . -type f -name "*.log" -exec rm {} \;

(其實我加上-type f有點多餘,因為我已經指定-name "*.log"了,就不可能輸出資料夾了。)

如果刪檔案的時候,一直要你按yes,可以這樣

yes | find . -type f -name "*.log" -exec rm {} \;

yes這個指令會一直串流輸出yes,這樣刪檔案就自動一直輸入yes

例子中find找到的檔案,就放到-exec\;之間的指令去處理,譬如找到了檔案develop.log,就會變成

rm develop.log

另外,{}並不是規定只能出現一次,譬如你要將資料夾內所有檔案加上副檔名log,可以這麼做

find . -type f -exec mv {} {}.log \;

這指令會包含子資料前內的檔案都加上.log副檔名。如果只想要目前資料夾的檔案,所以可以加上-maxdepth 1,若要地回到下一層資料夾可以將1改成2,3或4以此類推

find . -maxdepth 1 -type f -exec mv {} {}.log \;

因此,若要批次改變檔案的內容,就可以搭配find -execsed -i。sed 加上 -i 參數,代表直接對檔案內容做修改。

我常常在幫別人複製或移動網站,很多人的網址都寫成包含域名的絕對路徑,所以常常要用這個指令去找出所有含舊域名的檔案,並改成新域名。

譬如舊域名為http://www.old.com,要改成http://www.new.com,我會這麼做

find . -type f -exec sed -i 's/www.old.com/www.new.com/g' {} \;

(sed這個指令在OS X上面如果照上例那樣執行,會有錯誤訊息。詳細請參考stackoverflow上面的討論)

這樣子會找遍所有的檔案,需要的時間有點久。我會再加上參數-not -name "不需要的檔名",來排除一些不需要尋找的檔案

find . -type f -not -name "*.log" -not -name "*.jpg" -exec sed -i 's/www.old.com/www.new.com/g' {} \;

像這樣跳過所有的log檔與jpg圖檔,有需要可以加上其他如-not -name "*.png",才加快速度。或者乾脆指定-name "*html"-name "*.php",只尋找相關網頁檔。

xargs

xargs使用起來就沒有像find -exec可以將檔名以{}的形式傳給指令去安排。xargs只能收管線資料當成指令參數來執行。

雖然使用上沒有靈活,但管線指令就是他的優點,所以他不只可以搭配find指令,echo資料給他也可以,譬如

echo a b c d e | xargs touch

一次創造了a b c d e五個檔案。如果find後面不用-exec,可以改用管線指令傳給xargs,譬如本篇第一個刪除檔案的例子,改用xargs變成

find -name "*.log" | xargs rm

但是後面改檔名的例子,就沒辦法這麼簡單的處理(可以處理,但改用xargs還要搭配其他指令,本篇已經太長,不再節外生枝介紹)

另外像改檔案內容的指令,因為檔名參數接在最後面,所以也可以很簡單的改用xargs來處理

find . -type f | xargs sed -i 's/www.old.com/www.new.com/g'

因此,當我用find在處理檔案時,我會用find -exec比較靈活。其他情況下我就用管線串流到xargs來處理

沒有留言:

張貼留言