更快地列出具有相似名称的文件(使用bash)?

时间:2018-03-13 05:55:08

标签: bash

我有一个包含超过20K文件的目录,所有文件都带有随机数前缀(例如12345 - name.jpg)。我想找到具有相似名称的文件并删除除一个之外的所有文件。我不在乎哪一个,因为它们是重复的。

要查找重复的名称,我使用

rm $(ls -1 *name.jpg | tail -n +2)

作为for / next循环的列表。

要查找除一个以外的所有内容,我目前正在使用

separate reducer

此操作非常慢。我想加快速度。有什么建议吗?

3 个答案:

答案 0 :(得分:0)

我会这样做。

*请注意,您正在处理rm命令,因此请确保备有现有目录,以防出现问题。

  1. 创建备份目录并备份现有文件。 完成后,请检查所有文件是否都在那里。

    mkdir bkp_dir;cp *.jpg /bkp_dir
    
  2. 创建另一个临时目录,我们将为每个相似的名称保留所有只有1个文件。所以所有独特的文件名都在这里。

    $ mkdir tmp
    $ for i in $(ls -1 *.jpg|sed 's/^[[:digit:]].*--\(.*\.jpg\)/\1/'|sort|uniq);do cp $(ls -1|grep "$i"|head -1) tmp/ ;done
    
  3. *命令的说明就在最后。执行后,如果您拥有文件的唯一实例,请检入/ tmp目录。

    1. 从主目录中删除所有*.jpg个文件。 再说一遍,请在执行rm命令之前验证是否已备份所有文件。

      rm *.jpg
      
    2. 从临时目录备份唯一实例。

      cp tmp/*.jpg .
      
    3. 步骤2中的命令说明。

      • 获取步骤2的唯一文件名的命令将是

        for i in $(ls -1 *.jpg|sed 's/^[[:digit:]].*--\(.*\.jpg\)/\1/'|sort|uniq);do cp $(ls -1|grep "$i"|head -1) tmp/ ;done

      • $(ls -1 *.jpg|sed 's/^[[:digit:]].*--\(.*\.jpg\)/\1/'|sort|uniq)将获得唯一的文件名,例如file1.jpg , file2.jpg

      • for i in $(...);do cp $(ls -1|grep "$i"|head -1) tmp/ ;done会将每个文件名的一个文件复制到tmp /目录。

答案 1 :(得分:0)

假设没有涉及子目录且没有涉及空格的文件名:

find . -type f -name "*.jpg" | sed -e 's/^[0-9]*--//' | sort | uniq -d > namelist 
removebutone () { shift; echo rm "$@"; }; cat namelist | while read n; do removebutone "*--$n"; done 

或更好的可读性:

removebutone () { 
  shift
  echo rm "$@"
}
cat namelist | while read n; do removebutone "*--$n"; done 

Shift从$ * off获取第一个参数。

请注意,名称parmeter周围的parens是超级的,并且sed之前不应该有两个管道。也许你还有别的东西需要被覆盖。

如果它看起来很有希望,你当然要删除'rm'前面的'echo'。

答案 2 :(得分:0)

You should not be using ls in scripts并且没有理由使用单独的文件列表,例如在userunknown的回复中。

keepone () {
    shift
    rm "$@"
}
keepone *name.jpg

如果您正在运行find来识别要隔离的文件,那么遍历目录两次效率很低。直接过滤find的输出。

find . -type f -name "*.jpg" |
awk '{ f=$0; sub(/^[0-9]*--/, "", f); if (a[f]++) print }' |
xargs echo rm

如果结果看起来与预期相符,请取出echo

顺便说一下,/g的{​​{1}}标志对于只能匹配一次的正则表达式是无用的。该标志表示替换行上的所有出现而不是行上的第一个出现,但如果只有一个,则第一个等同于全部。