多个目录中的相同文件名:如何仅用一个命令同时为它们分配不同的名称?

多个目录中的相同文件名:如何仅用一个命令同时为它们分配不同的名称?

我有 23 个不同的目录,每个目录中都有一个名为accepted_hits.bam 的文件

所以我需要在每个目录中生成一个唯一的名称:例如目录1的accepted_hits.bam_1 目录2的accepted_hits.bam_2

如此反复23次。有没有一种简单的方法可以用一个命令来做到这一点?

答案1

bashfind

find . -type f -name accepted_hits.bam -exec bash -c \
'i=0; for f; do (( ++i )); mv -- "$f" "${f}_$i"; done' _ {} +

答案2

假设您的目录都位于同一父目录,请尝试以下操作:

$ for f in $(ls */accepted_hits.bam); do mv $f $(dirname $f)/$(dirname $f)-$(basename $f); done

答案3

我可能会使用awk,但这只是一个品味问题,而不是对与错:

find . -name accepted_hits.bam | awk '{ print "cp -pi \"" $0 "\" \"" $0 "\"_" NR "; mv -i \"" $0 "\"_" NR " ./bam-files/" }' | tcsh -f

您需要./bam-files/在调用上面的行之前创建一个目录,或者调整目录名称。我特意用于-p保留文件时间并-i避免覆盖,以防万一。因此,在第二次调用命令之前,请清理目标目录。

如果您想删除原始文件,cp -pi请将mv -i.

该脚本省略了对 的调用,basename希望在路径名包含特殊字符(空格和大多数特殊字符均已处理)时减少遇到的麻烦。

PS:您也可以在执行之前进行试运行,方法是省略| tcsh -cf最后的 。如果您还没有tcsh安装(是的,有一些 Linux 没有安装它),请随意使用shbash

答案4

使用 shell glob 可以很容易做到这一点:

  1. 将计数器添加到名称(accepted_hits.bam.1accepted_hits.bam.2):

    c=0; for f in */accepted_hits.bam; do mv "$f" "$f".$((++c)); done
    

    解释

    这只是迭代accepted_hits.bam当前目录子目录中所有被调用的文件,并将每个文件保存为$f.该$((++c))构造会递增计数器 ( $c),因此等$f.$((++c))将在每次迭代时递增。file.1file.2

    请注意,我c=0在一开始就使用了。如果您不这样做,后续运行将保留 的值$c并且它将继续递增。

  2. 在扩展名之前添加一个计数器(accepted_hits.1.bamaccepted_hits.2.bam等等):

    c=0; for f in */accepted_hits.bam; do  
        mv "$f" "$(dirname "$f")"/"$(basename "$f" .bam)".$((++c)).bam
    done
    

    解释

    该命令dirname返回文件父目录的路径:

    $ dirname /usr/local/bin/apt 
    /usr/local/bin
    

    该命令basename是相反的,它删除目录,只保留路径的最后一部分,还可以删除扩展名:

    $ basename /etc/apt/sources.list
    sources.list
    $ basename /etc/apt/sources.list .list   ## remove extension
    sources
    

    因此,mv "$f" "$(dirname "$f")"/"$(basename "$f" .bam)".$((++c)).bam将根据需要重命名该文件。

  3. 添加父目录的名称(accepted_hits.dir1.bamaccepted_hits.dir2.bam或任何您的目录名称)

    for f in */accepted_hits.bam; do  
        dir="$(dirname "$f")"; mv "$f" "$dir"/"$(basename "$f" .bam)"."$dir".bam
    done
    

    解释

    这与上面的想法相同,只是我将目录名称保存为变量以简化将其用作文件名的一部分。

  4. 使用外部工具。以Perlrename为例。基于 Debian 的发行版附带的标准rename无法处理递增计数器。然而,我发现这个哪个行。下载该页面中链接的脚本,将其保存increname在当前目录中并按如下方式运行:

    perl increname -n 's/.bam/++$c . ".bam"/e' */accepted_hits.bam 
    

相关内容