根据另一个文件重命名多个文件

根据另一个文件重命名多个文件

我有一个包含约 300 个文件的文件夹

PD26414b.fixedheader.hs37d5.cram
PD26414b.fixedheader.hs37d5.cram.crai
PD26415g.fixedheader.hs37d5.cram
PD26415g.fixedheader.hs37d5.cram.crai

我想将文件名中的 ID(PD26414b、PD26415g)替换为我保存在文本文件中的同源名称

head names.homologs.txt
PD26414b SAMEA3471115
PD26415g SAMEA3471120
PD26433c SAMEA3471126
PD26429d SAMEA3471130

因此PD26414b的同系物名称是SAMEA3471115。

我想要的文件名是

SAMEA3471115.fixedheader.hs37d5.cram
SAMEA3471115.fixedheader.hs37d5.cram.crai
SAMEA3471120.fixedheader.hs37d5.cram
SAMEA3471120.fixedheader.hs37d5.cram.crai

有什么办法可以在Linux下做到这一点吗?我知道它应该是 sed 和 mv 的组合,但不知道确切的命令

答案1

如果未安装重命名实用程序,我们始终可以推出自己的重命名实用程序,但没有任何附加功能:

perl -le 'local $/;
  my %h = <STDIN> =~ /^(.*) (.*)$/mg;
  rename $_, s/^[^.]+/$h{$&}/r
    for @ARGV;
' *cram* < names.homologs.txt

使用 Pearl 的标准输入上的同源文件,我们可以在其中初始化名称映射哈希并将其应用到后续的重命名命令中。


我们可以尝试使用 sed 来完成此操作,因为文件名中没有换行符

sed -Ee '
  1i\
h
  s|\S+|s/^[.][/]&[.]/|
  s||.\\/&./;ta|2
$a\
:a\
G\
s/(.*)\\n(.*)/\\2 \\1/
' names.homologs.txt > genMvPairs

  find . -maxdepth 1 -type f -name '*.cram*' |
  sed -Ef genMvPairs - | xargs -n2 -t mv -f

答案2

如果您在 Linux 计算机上或以其他方式可以访问 perl rename 命令(这可以称为renameorprename或 ,perl-rename具体取决于操作系统),并且假设 ID 中永远不能有空格或其他空白,您可以执行以下操作:

while read id hom; do
    rename -n "s/^$id/$hom/" "$id".*
done < names.homologs.txt

这只会打印它将执行的操作,但实际上不会重命名任何内容。一旦您检查它是否满足您的要求,请再次运行它,而无需-n选择实际进行更改。


或者,您也可以在 shell 中执行以下操作:

while read id hom; do
    for file in "$id".*; do
        newFile=$(printf '%s\n' "$file" | sed "s/$id/$hom/")
        mv -- "$file" "$newFile"
    done
done < names.homologs.txt

但请注意,这假设不会出现名称冲突(如果文件的新名称对应于现有文件的名称,则现有文件将被覆盖),文件名中没有换行符(实际上应该是使用临时文件进行安全假设)。

答案3

事实证明这与下半年相似特登的回答,但我正在使用一种更安全、更快捷的方法来计算文件的新名称。

使用/bin/sh

#!/bin/sh

while read -r id homolog; do
        for oldname in "$id".*; do
                [ -e "$oldname" ] || continue
                newname=$homolog.${oldname#$id.}
                mv -- "$oldname" "$newname"
        done
done <names.homologs.txt

这假设我们要重命名的文件位于当前目录中。该脚本将文件每一行中的两个字符串读取names.homologs.txt到两个变量id和中homolog

对于每个id,它尝试循环"$id".*当前目录中名称匹配的文件。对于每个这样的文件,如果它确实存在,则通过将$id.我们知道位于字符串开头的部分替换为$homolog..然后使用该mv实用程序实际重命名该文件。

不检查名称冲突。

答案4

一个纯粹的bash解决方案,提供为 @terdon 说文件名中没有奇怪的字符,也没有大量的同源物:

#!/usr/bin/env bash

declare -a homologs

while read key val
do {
  homologs["$key"]="$val"
} done < names.homologs.txt


while read file
do
# key is the part before the dot
  key="${file%%.*}"
# end is part after the first dot to the end
  end="${file#*.}"
  printf 'mv -- "%s" "%s.%s"\n' "${file}" "${homologs["$key"]}" "$end"
done

相关内容