我有 23 个不同的目录,每个目录中都有一个名为accepted_hits.bam 的文件
所以我需要在每个目录中生成一个唯一的名称:例如目录1的accepted_hits.bam_1 目录2的accepted_hits.bam_2
如此反复23次。有没有一种简单的方法可以用一个命令来做到这一点?
答案1
与bash
和find
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 没有安装它),请随意使用sh
或bash
。
答案4
使用 shell glob 可以很容易做到这一点:
将计数器添加到名称(
accepted_hits.bam.1
等accepted_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.1
file.2
请注意,我
c=0
在一开始就使用了。如果您不这样做,后续运行将保留 的值$c
并且它将继续递增。在扩展名之前添加一个计数器(
accepted_hits.1.bam
,accepted_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
将根据需要重命名该文件。添加父目录的名称(
accepted_hits.dir1.bam
、accepted_hits.dir2.bam
或任何您的目录名称)for f in */accepted_hits.bam; do dir="$(dirname "$f")"; mv "$f" "$dir"/"$(basename "$f" .bam)"."$dir".bam done
解释
这与上面的想法相同,只是我将目录名称保存为变量以简化将其用作文件名的一部分。
使用外部工具。以Perl
rename
为例。基于 Debian 的发行版附带的标准rename
无法处理递增计数器。然而,我发现这个哪个行。下载该页面中链接的脚本,将其保存increname
在当前目录中并按如下方式运行:perl increname -n 's/.bam/++$c . ".bam"/e' */accepted_hits.bam