在 Linux 中的指令通常都有一些參數可以指定,而在 Shell 中一行指令的長度是有上限的,在大部分的狀況下,這個限制通常是不會造成什麼問題的,不過在某些參數特別多的狀況下,可能就會碰到這個限制,例如要用 rm
或 mv
指令刪除或搬移很多檔案的時候,如果指定的檔案數量太多,有可能就會發生參數過長的錯誤,就像這樣:
Argument list too long
在不同的系統中,命令列的長度上限是不同的,這裡介紹如何找出自己系統的命令列長度上限,並且教大家在撰寫指令稿時,如何使用一些替代方案避開參數過長的問題。
查詢命令列長度上限
在一般的 UNIX、Linux 或 BSD 系統中,如果想查詢命令列的長度上限,可以使用 getconf
這個指令:
getconf ARG_MAX
輸出會像這樣:
2097152
而在 BSD 的系統中,也可以使用 sysctl
指令:
sysctl kern.argmax
這個輸出會像這樣:
kern.argmax=262144
而上面這些值是整個命令列的長度上限,事實上還包含了一些環境變數,如果想知道實際上在執行指令時,可以輸入的長度,可以用這個方式扣掉環境變數用掉的部分:
echo $(( $(getconf ARG_MAX) - $(env | wc -c) ))
輸出為:
2095122
這個值就是輸入指令時真正可以用的最大長度。
指令太長的解決方式
如果你要執行的指令長度超過容許的上限,基本上有兩種方式可以解決:
- 使用
find
與xargs
指令。 - 使用 Shell 的
for
或while
迴圈。
使用 find
指令,列出 /nas/data/accounting/
的檔案:
find /nas/data/accounting/ -type f -exec ls -l {} \;
刪除 /nas/data/accounting/
的檔案:
find /nas/data/accounting/ -type f -exec /bin/rm -f {} \;
使用 xargs
的方式:
echo /nas/data/accounting/* | xargs ls -l echo /nas/data/accounting/* | xargs /bin/rm -f
使用 while
迴圈:
ls -1 /nas/data/accounting/ | while read file; do mv /nas/data/accounting/$file /local/disk/ ; done
將上面的各種方式放在一起:
find /nas/data/accounting/ -type f | while read file do mv /nas/data/accounting/$file /local/disk/ done
參考資料:nixCraft