【问题标题】:How to rename multiple files with similar strings separated by periods and underscores with the rename command如何使用重命名命令重命名具有相似字符串的多个文件,这些字符串由句点和下划线分隔
【发布时间】:2020-04-17 02:16:25
【问题描述】:

Ubuntu 16.04
重击 4.4.20
重命名 0.20

我每天都有数百个文件被复制到一个文件夹中。文件夹名称每天都不一样,所以文件夹里面的文件必须重命名

这是复制到文件夹后的文件示例。

2019-11-30_hs5_felix.doggie.com_1112.garage
2019-12-01_hs5_ralph.doggie.com_1112.garage
2019-12-04_hs5_sartah.doggie.com_1112.garage
2019-12-05_hs5_felix.doggie.com_1112.garage
2019-12-07_hs5_ggg.doggie.com_1112.garage
2019-12-12_hs5_fex.doggie.com_1112.garage
2019-12-19_hs5_sioia.doggie.com_9999.garage
2019-12-21_hs5_felix.doggie.com_1002.garage
2019-12-22_hs5_sonia.doggie.com_1112.garage
2019-12-25_hs5_isabel.doggie.com_1106.garage  

这是相同的模式:

same_same_"${one}".same.same_"${two}".same

因此变量将代表我们将用来重命名所有文件的两个词,并且重命名后的文件需要如下所示:

one="ssss"
two="1234"

2019-11-30_hs5_sssss.doggie.com_1234.garage
2019-12-01_hs5_sssss.doggie.com_1234.garage
2019-12-04_hs5_sssss.doggie.com_1234.garage
2019-12-05_hs5_sssss.doggie.com_1234.garage
2019-12-07_hs5_sssss.doggie.com_1234.garage
2019-12-12_hs5_sssss.doggie.com_1234.garage
2019-12-19_hs5_sssss.doggie.com_1234.garage
2019-12-21_hs5_sssss.doggie.com_1234.garage
2019-12-22_hs5_sssss.doggie.com_1234.garage
2019-12-25_hs5_sssss.doggie.com_1234.garage

最终产品比如何完成更重要,因此我们可以使用任何命令到达那里。

【问题讨论】:

  • Ubuntu 版本和 Bash 版本都不错,但不要告诉我们您系统上的 rename 命令。有两个独立的 Linux rename 命令功能非常不同。一个来自util-linux 包(不支持正则表达式匹配)和perl-rename 支持。显示rename --version的输出。
  • @DavidC.Rankin 重命名版本 0.20。我在看你的回答。你所做的所有解释就是我每天回到这个网站的原因。
  • 如果您有任何问题,请告诉我,我很乐意进一步解释。我查看了使用rename,但使用 util-linux 版本,您只能替换第一次出现的表达式。在您的情况下,您需要替换两个表达式。这意味着 perl-rename 将是唯一的选择——但你仅限于需要该软件包——许多发行版不包括该软件包。您通常会找到sed。您也可以仅使用 bash 参数扩展 进行部分替换——这是另一个不错的选择。

标签: bash sed rename


【解决方案1】:

如果不重命名,您实际上可以更改文件的名称,使用 mv 命令和 command-substitution 使用 sed 进行 "$one""$two" 的替换。这消除了“我有哪个版本的重命名?”

例如,在您的情况下,您可以切换到包含文件的目录,然后执行以下操作:

one="ssss"
two="1234"

for i in *; do 
    mv "$i" "$(sed 's/^\(.*hs5_\)[^.]*\([.].*com_\)[0-9]*\(.*$\)/\1'"$one"'\2'"$two"'\3/' <<< "$i")"
done

其中使用了sed 普通替换命令,利用了三捕获组和反向引用。

说明

sed 替换命令是 sed 's/find/replace/',在您的情况下,查找被分成几个部分:

  • ^\(.*hs5_\) 匹配从文件名开头到"hs5_" 捕获\( ... \) 捕获组中的文本,使用基本正则表达式重新插入第一个反向引用\1
  • "hs5_" 开始,我们匹配[^.]* 不包含'.' 的字符序列;
  • 然后我们从'.'"com_" 捕获\([.].*com_\) 以重新插入第二个反向引用\2;最后
  • 使用\(.*$\) 捕获文件名末尾的所有字符以重新插入为\3

对于替换部分,我们只包含捕获的文本进行变量替换:

  • \1'"$one"'\2'"$two"'\3

(注意:引用非常具体。sed 命令的部分用单引号括起来,shell 变量用双引号括起来,以及完整的命令替换。

文件的基本移动通过mv "$i" "$(sed ... &lt;&lt;&lt; "$i") 完成,其中文件名被提供给sed 命令使用仅bash Here-String &lt;&lt;&lt; 重定向的内容stdin 上的 sed 命令的变量,允许 sed 进行替换以完成移动。

【讨论】:

    【解决方案2】:

    按照same_same_"${one}".same.same_"${two}".same的模式,怎么样:

    one="ssss"
    two="1234"
    for f in *.*; do
        IFS=_ read -ra a <<< "$f"
        a[2]="${one}.${a[2]#*.}"
        a[3]="${two}.${a[3]#*.}"
        (IFS=_; mv -- "$f" "${a[*]}")
    done
    

    它首先拆分_上的文件名,将指定位置替换为 变量,然后将它们再次合并为新文件名。

    【讨论】:

      【解决方案3】:

      这也可能对您有用 - (GNU 并行):

      parallel 'mv {1} {=1 s/(_.*_)[^.]+(.*_)[^.]+/$1$arg[2]$2$arg[3]/ =}' ::: * ::: ssss ::: 1234
      

      使用 GNU 并行消除 forloop 和 shell 变量。 {=n ... =} 允许在第 n 个位置替换字符串上使用 perl 命令。在这种情况下,请使用替换命令替换从::: * 获取的每个文件名的部分内容。

      注意:在执行此命令之前,最好插入--dry-run 选项并在实时运行之前检查其输出。

      【讨论】:

      • 你的例子很受欢迎。
      【解决方案4】:

      我为你的文件名提出了这个 (2019-12-19_hs5_sioia.doggie.com_9999.garage)

      one="ssss"
      two="1234"
      
      for file in *; { name=${file//_[0-9]*.g/_$two.g}; name=${name//_*.d/_$one.d}; mv $file $name; }
      

      此方法使用变量替换 ${var//pattern/change}

      【讨论】:

        猜你喜欢
        • 2020-06-07
        • 2021-10-24
        • 2016-04-02
        • 1970-01-01
        • 2015-05-19
        • 2011-12-27
        • 1970-01-01
        • 2012-11-28
        • 2017-05-26
        相关资源
        最近更新 更多