Linux命令中的“引數列表過長”錯誤


概述

在本文中,我們將討論在您嘗試在 Linux 系統上執行命令時顯示的錯誤訊息,該訊息顯示為“引數列表過長”。此錯誤可能由多種原因造成。在本篇文章中,我將解釋導致此錯誤的原因以及如何解決它。

什麼是“引數列表過長”錯誤?

此錯誤是由於向程式或 shell 指令碼傳遞了無效的引數而發生的。這意味著程式允許的引數數量超過了限制。例如,如果您執行以下命令:

ls -l /usr/bin/* | grep binutils

您可能會收到以下錯誤:

-bash: /usr/bin/grep: Argument list too long

如果您想知道上述命令失敗的原因,請繼續閱讀。

導致錯誤的原因是什麼?

我們將研究一個目錄中有很多檔案的情況。

$ ls -lrt | wc -l
230086

$ ls -lrt | tail -5
-rw-r--r-- 1 shubh shubh 0 Nov 30 14:02 events2120038.log
-rw-r--r-- 1 shubh shubh 0 Nov 30 14:02 events2120040.log
-rw-r--r-- 1 shubh shubh 0 Nov 30 14:02 events2120039.log
-rw-r--r-- 1 shubh shubh 0 Nov 30 14:02 events2120042.log
-rw-r--r-- 1 shubh shubh 0 Nov 30 14:02 events2120041.log

我們的資料夾中有超過 230K 個日誌檔名。讓我們看看我們能否獲得以單詞“events”開頭的檔案數量。

$ ls -lrt events* | wc -l
-bash: /usr/bin/ls: Argument list too long
0

值得注意的是,命令失敗,並以“引數列表過長”為由。讓我們嘗試使用 rm 命令來刪除這些檔案:

$ rm -rf events*.log
-bash: /usr/bin/rm: Argument list too long

該命令再次因為同樣的原因失敗。

在執行檔名擴充套件時,Bash 執行一個稱為“擴充套件”的操作,這意味著它將 * 字元與每個匹配的檔名擴充套件。結果,Bash 建立了一個非常長的引數字串,它無法處理。

如果作為命令列引數擴充套件的檔案過多,Bash 可能無法處理它們。請注意,此緩衝區(引數緩衝區)與環境變數資訊共享,因此實際可用記憶體小於此緩衝區。

之前的示例中的 rmdir(刪除目錄)命令擴充套件為:

$ rm -rf events2120038.log events2120040.log ... events0000001.log

這裡,引數向量變得比檔案中的行數更多。為避免參數過多,我們使用 getcwd() 函式獲取當前工作目錄(從檔案系統根目錄到我們當前位置的路徑)。然後,我們使用 getargs() 函式從檔案的每一行提取第一個引數。最後,我們使用 strlen() 函式確定結果字串的長度。

$ getconf ARG_MAX
2097152

ARG_max 引數確定 exec() 函式所需的最大空間。它允許核心知道執行程式所需的最大緩衝區。您可以使用 xargs 命令驗證這些限制。

$ xargs --show-limits
Your environment variables take up 2504 bytes
POSIX upper limit on argument length (this system): 2092600
POSIX smallest allowable upper limit on argument length (all systems): 4096
Maximum length of command we could actually use: 2090096
Size of command buffer we are actually using: 131072
Maximum parallelism (--max-procs must be no greater): 2147483647

關於引數長度上限最重要的一點是,它們在不同的作業系統之間可能有所不同。

克服限制

我們將研究解決此問題的不同方法。所有這些方法都涉及避免參數擴充套件。

使用find命令

您可以使用 find 命令迭代檔名,並使用 exec 選項或 xargs 命令逐個執行它們。

$ find . -iname "events*" | xargs ls -lrt | wc -l
230085

我們首先使用 find 命令獲取包含字串“events”的檔名。接下來,我們將 find 命令的輸出傳遞給 xargs 命令。最後,我們對 xargs 命令的結果執行 ls 和 wc 命令。

使用for迴圈方法

您可以使用另一種方法透過 for 迴圈迭代檔案。

$ for f in events*; do echo "$f"; done | wc -l
230085

這是解決此問題的幾個簡單解決方案之一。它可能比其他方法花費更長時間,但它效果很好。

手動分割

我們可以將檔案分割成更小的塊,並使用不同的字串集作為引數在每次迭代中重複執行命令。

$ ls -lrt events1*.log | wc -l
31154

$ ls -lrt events2*.log | wc -l
15941

我們只過濾名稱以“events1”開頭的檔案。在這種特定情況下,我們保持在 ARG_MAX 變數設定的限制範圍內。

然後,我們對以“event1”、“event2”等開頭的檔案重複相同的步驟。

當我們只需要刪除目錄的內容時

如果我們嘗試從目錄中刪除所有檔案,那麼考慮一下我們無法做到這一點的情況:

$ rm -rf *
-bash: /usr/bin/rm: Argument list too long

如果我們想解決這個問題,我們可以改為刪除目錄並重新建立它。

$ rm -rf /home/shubh/tempdir/logs_archive
$ cd home/shubh/tempdir && mkdir logs_archive

這裡,logs_archive 資料夾包含我們要刪除的檔案。

由於我們正在刪除資料夾並重新建立它,因此這種方法不會保留資料夾的原始許可權設定或所有權。

結論

我們研究了幾種處理“過長”問題的方法。

我們首先討論了導致此問題的原因,然後研究了一些解決方法。

更新於:2022年12月26日

2K+ 次檢視

啟動您的職業生涯

透過完成課程獲得認證

開始
廣告
© . All rights reserved.