在 Linux 中的指令通常都有一些參數可以指定,而在 Shell 中一行指令的長度是有上限的,在大部分的狀況下,這個限制通常是不會造成什麼問題的,不過在某些參數特別多的狀況下,可能就會碰到這個限制,例如要用 rmmv 指令刪除或搬移很多檔案的時候,如果指定的檔案數量太多,有可能就會發生參數過長的錯誤,就像這樣:
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
這個值就是輸入指令時真正可以用的最大長度。

指令太長的解決方式

如果你要執行的指令長度超過容許的上限,基本上有兩種方式可以解決:

  • 使用 findxargs 指令。
  • 使用 Shell 的 forwhile 迴圈。

使用 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