我在UNIX的一个目录下有几百个PDF。PDF的名称非常长(约60个字符)。

当我尝试使用以下命令一起删除所有PDF时:

rm -f *.pdf

我收到以下错误:

/bin/rm: cannot execute [Argument list too long]

此错误的解决方案是什么?mv和cp命令是否也会出现此错误?如果是,如何解决这些命令?


当前回答

对于没有时间的人。在终端上运行以下命令。

ulimit -S -s unlimited

然后执行cp/mv/rm操作。

其他回答

你可以用这个表扬

find -name "*.pdf"  -delete

参数列表太长

作为cp、mv和rm的问题标题,但答案主要代表rm。

Un*x命令

仔细阅读命令的手册页!

对于cp和mv,有一个-t开关,用于目标:

find . -type f -name '*.pdf' -exec cp -ait "/path to target" {} +

and

find . -type f -name '*.pdf' -exec mv -t "/path to target" {} +

脚本方式

bash脚本中使用了一个整体解决方案:

#!/bin/bash

folder=( "/path to folder" "/path to anther folder" )

if [ "$1" != "--run" ] ;then
    exec find "${folder[@]}" -type f -name '*.pdf' -exec $0 --run {} +
    exit 0;
fi

shift

for file ;do
    printf "Doing something with '%s'.\n" "$file"
done

我也遇到了同样的问题,因为一个文件夹中的临时图像与日俱增,这个命令帮助我清除了这个文件夹

find . -name "*.png" -mtime +50 -exec rm {} \;

与其他命令的不同之处在于mtime参数,该参数将只接受早于X天的文件(在示例中为50天)

多次使用这种方法,减少每天执行的次数,我能够删除所有不必要的文件

我发现对于非常大的文件列表(>1e6),这些答案太慢了。这里有一个在python中使用并行处理的解决方案。我知道,我知道,这不是linux。。。但这里没有其他办法奏效。

(这节省了我几个小时)

# delete files
import os as os
import glob
import multiprocessing as mp

directory = r'your/directory'
os.chdir(directory)


files_names = [i for i in glob.glob('*.{}'.format('pdf'))]

# report errors from pool

def callback_error(result):
    print('error', result)

# delete file using system command
def delete_files(file_name):
     os.system('rm -rf ' + file_name)

pool = mp.Pool(12)  
# or use pool = mp.Pool(mp.cpu_count())


if __name__ == '__main__':
    for file_name in files_names:
        print(file_name)
        pool.apply_async(delete_files,[file_name], error_callback=callback_error)

tl;博士

这是命令行参数大小的内核限制。请改用for循环。

问题的根源

这是一个系统问题,与execve和ARG_MAX常量有关。有很多关于这方面的文档(参见man execve、debian的wiki、ARG_MAX详细信息)。

基本上,扩展生成的命令(及其参数)超过ARG_MAX限制。在内核2.6.23中,限制设置为128 kB。此常数已增加,您可以通过执行以下操作获取其值:

getconf ARG_MAX
# 2097152 # on 3.5.0-40-generic

解决方案:使用for循环

按照BashFAQ/095上的建议使用for循环,除了RAM/内存空间之外没有其他限制:

试运行以确定它将删除您期望的内容:

for f in *.pdf; do echo rm "$f"; done

并执行它:

for f in *.pdf; do rm "$f"; done

这也是一种可移植的方法,因为glob在shell之间具有强大且一致的行为(POSIX规范的一部分)。

注意:正如几条评论所指出的,这确实较慢,但更易于维护,因为它可以适应更复杂的场景,例如,一个人要做的不止一个动作。

解决方案:使用find

如果您坚持,您可以使用find,但实际上不要使用xargs,因为它“在读取非NUL分隔的输入时很危险(损坏、可利用等)”:

find . -maxdepth 1 -name '*.pdf' -delete 

使用-maxdepth 1-delete而不是-exec rm{}+允许find在不使用外部进程的情况下简单地执行所需的系统调用,因此速度更快(多亏了@chepner注释)。

工具书类

我得到了“参数列表太长”。如何处理大块列表?@羊毛边的execve(2)-Linux手册页(搜索ARG_MAX);错误:参数列表太长@Debian的wiki;为什么在传递带引号的参数时会得到“/bin/sh:参数列表太长”?@超级用户