iT邦幫忙

2

【Linux小筆記】用xargs處理Argument list too long的錯誤以及其原理

最近要刪除 /tmp 底下的檔案,下了 rm *.log 突然跳出 Argument list too long

這個錯誤,查了一下,原來是檔案數量太多,超過Linux 允許作為 rm 參數的範圍,而被報錯了。

知道原因後,繼續找了方法,查到可以用下面的語法來解決:

find . -name "*.log" | xargs rm

前面用 find 是不難理解,後面的 xargs 看上去就有點陌生了,查了一下 xargs的定義

NAME

xargs - build and execute command lines from standard input

DESCRIPTION

This manual page documents the GNU version of xargs. xargs reads items from the standard input, delimited by blanks (which can be protected with double or single quotes or a backslash) or newlines, and executes the command (default is /bin/echo) one or more times with any initial-arguments followed by items read from standard input. Blank lines on the standard input are ignored.

Because Unix filenames can contain blanks and newlines, this default behaviour is often problematic; filenames containing blanks and/or newlines are incorrectly processed by xargs. In these situations it is better to use the -0 option, which prevents such problems. When using this option you will need to ensure that the program which produces the input for xargs also uses a null character as a separator. If that program is GNU find for example, the -print0 option does this for you.

If any invocation of the command exits with a status of 255, xargs will stop immediately without reading any further input. An error message is issued on stderr when this happens.

意思是說 xargs 可以把標準輸入作為來源,然後執行它後面的命令。所以以上面的命令來說,它是將 find找到的結果,透過 pipeline 將輸出轉成輸入,轉給xargs使用。

不過即使如此,乍看之下也不知道這樣和 rm *.log 有什麼實際上的差別,為什麼轉一手給 xargs就不會跳出 Argument list too long ?

這個就要深入到 xargs 的原理了,在 你真的了解xargs命令吗 這篇文章中,深入去討論 xargs 的運作方式,他作對上面 DESCRIPTION中:

executes the command (default is /bin/echo) one or more times

這段話,實際去驗證究竟會執行幾次,發現 xargs 使用的 命令一次會被調用 2000~ 4000次左右,因此,如果列出的log有一萬筆的話,可能就會被分成 3到 5次左右來執行,因而避開了 Argument list too long 的錯誤。

在查詢的過程中,也發現了一篇不錯的文章 玩转 xargs 一起分享給邦友。如果邦友有什麼使用 xargs 上的妙用,也歡迎分享給小弟知道。


1 則留言

1
weiclin
iT邦高手 4 級 ‧ 2016-05-20 23:03:26

如果你想要一個一個檔案做處理的話, 用 for .. in 也挺好用的

for f in /tmp/*; do echo "going to do: rm $f"; rm $f; done

我要留言

立即登入留言