首页 > 解决方案 > 使用ls查找满足条件的list文件

问题描述

我正在编写一个批处理程序来删除具有文件名条件的目录中的所有文件。

目录中有大量文本文件(约数十万个文件),文件名固定为“abc”+日期

abc_20180820.txt
abc_20180821.txt
abc_20180822.txt
abc_20180823.txt
abc_20180824.txt

该程序尝试对所有文件进行grep,将日期与固定日期进行比较,如果文件名的日期<固定日期则将其删除。但问题是处理大量文件需要很长时间(删除 30 万个文件大约需要 1 小时)。

我的问题:有没有办法在运行 ls 命令时比较日期?不获取列表中的所有文件然后比较删除,而是仅列出已经满足条件的文件然后删除。我认为这会有更好的表现。

我的代码是

   TARGET_DATE =  "5-12"
    DEL_DATE = "20180823"   
    ls -t |  grep "[0-9]\{8\}".txt\$ > ${LIST}
        for EACH_FILE in  `cat ${LIST}` ;
        do
            DATE=`echo ${EACH_FILE} | cut -c${TARGET_DATE }`
            COMPARE=`expr "${DATE}" \< "${DEL_DATE}"`
            if [ $COMPARE -eq 1 ] ;
            then
                rm -f ${EACH_FILE}
            fi
        done 

发现了一些类似的问题,但我不知道如何完成 使用带有条件的 ls 列出文件和仅包含空格的进程/grep 文件

标签: linuxbashshell

解决方案


这是一个摆脱讨厌的重构ls。循环一个大目录仍然会有点慢。

# Use lowercase for private variables
# to avoid clobbering a reserved system variable

# You can't have spaces around the equals sign
del_date="20180823"   

# No need for ls here
# No need for a temporary file
for filename in *[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9].txt
do
    # Avoid external process; use the shell's parameter substitution
    date=${filename%.txt}
    # This could fail if the file name contains literal shell metacharacters!
    date=${date#${date%?????????}}
    # Avoid expr
    if [ "$date" -lt "$del_date" ]; then
        # Just print the file name, null-terminated for xargs
        printf '%s\0' "$filename"
    fi
done |
# For efficiency, do batch delete
xargs -r0 rm

通配符扩展仍然需要相当长的时间,因为 shell 将对文件名列表进行排序。更好的解决方案可能是将其重构为find避免排序的命令。

find . -maxdepth 1 -type f \( \
      -name '*1[89][0-9][0-9][0-9][0-9][0-9][0-9].txt' \
   -o -name '*201[0-7][0-9][0-9][0-9][0-9].txt' \
   -o -name '*20180[1-7][0-9][0-9].txt ' \
   -o -name '*201808[01][0-9].txt' \
   -o -name '*2018082[0-2].txt' \
 \) -delete

推荐阅读