-bash: /usr/bin/mv: 參數列表太長

-bash: /usr/bin/mv: 參數列表太長

當我使用這個命令時mv * ..,我收到錯誤-bash: /usr/bin/mv: Argument list too long。我確實理解發生這種情況的原因是因為 bash 實際上將星號擴展到每個匹配的文件,產生一個非常長的命令行。我該如何修復這個錯誤?

答案1

限制不在 bash 中,而是在execve()用於執行外部命令的系統呼叫中。你可以這樣做:

printf '%s\0' * | xargs -r0 mv -t .. --

由於printf是內建的,所以此時bash沒有。execve()需要xargs分割參數清單以避免這種限制。這裡使用 GNU-t的 GNU特定選項mv

使用zsh,您可以加載mv內建:

zmodload zsh/files
mv -- * ..

或使用它的zargs助手來進行分割:

autoload -Uz zargs # best in ~/.zshrc
zargs -r -- ./* -- mv -t ..

您可以替換./*為來./*(D)移動隱藏文件,或者添加oNglob 限定符來跳過文件名排序,或者N添加 glob 限定符(帶有zargs -r)來避免在沒有匹配文件時出現錯誤。

zargs -r -- ./*(ND) -- mv -t ..

與...一樣:

print -rNC1 ./*(ND) | xargs -r0 mv -t ..

但不依賴 GNU xargs

在 Linux(通常在 Ubuntu 上使用的核心)上,您還可以execve()透過提高stacksize資源限制來提高該限制:

bash-5.1$ /bin/true {1..200000}
bash: /bin/true: Argument list too long
bash-5.1$ ulimit -s unlimited
bash-5.1$ /bin/true {1..200000}
bash-5.1$ 

它不是完全無限制的(至少在當前版本的核心中不是):

bash-5.1$ /bin/true {1..2000000}
bash: /bin/true: Argument list too long

請注意,限制在於傳遞給 的參數和環境變數的累積大小execve(),但計算不僅僅是其中位元組的總和,而且其完成方式因作業系統及其版本而異。

答案2

您可以透過兩個或更多步驟來完成:

mv [a-k]* ..    # or some other pattern matching a subset of the files
mv -- * ..

或在一個循環中,

for name in *; do
    mv -- "$name" ..
done

(但這需要mv單獨列出每個名字。)

或來find幫助您:

find . -mindepth 1 -maxdepth 1 -exec mv -t .. -- {} +

這將找到當前目錄中的所有名稱,並使用 GNU mv,以盡可能少的呼叫將它們移至上面的目錄mv

沒有 GNU mv,但find仍知道非標準-mindepth-maxdepth謂詞,

find . -mindepth 1 -maxdepth 1 -exec sh -c 'mv -- "$@" ..' sh {} +

這些變體都不關心名稱衝突。您應該對正確備份的資料進行測試。

相關內容