【问题标题】:Remove middle of filenames删除文件名中间
【发布时间】:2017-10-31 16:48:14
【问题描述】:

我在 bash 中有一个这样的文件名列表

UTSHoS10_Other_CAAGCC-TTAGGA_R_160418.R1.fq.gz
UTSHoS10_Other_CAAGCC-TTAGGA_R_160418.R2.fq.gz
UTSHoS11_Other_AGGCCT-TTAGGA_R_160418.R2.fq.gz
UTSHoS11_Other_AGGCCT-TTAGGA_R_160418.R2.fq.gz
UTSHoS12_Other_GGCAAG-TTAGGA_R_160418.R1.fq.gz
UTSHoS12_Other_GGCAAG-TTAGGA_R_160418.R2.fq.gz

我希望它们看起来像这样

UTSHoS10_R1.fq.gz
UTSHoS10_R2.fq.gz
UTSHoS11_R1.fq.gz 
UTSHoS11_R2.fq.gz
UTSHoS12_R1.fq.gz
UTSHoS12_R2.fq.gz

我没有 perl rename 命令和 sed 's/_Other*160418./_/' *.gz 没有做任何事情。我在这里尝试了其他重命名脚本,但要么没有任何反应,要么我的 shell 开始向控制台打印大量代码并冻结。

这篇文章 (Removing Middle of Filename) 类似,但是给出的答案并没有解释命令的具体部分在做什么,所以我无法将它应用于我的问题。

【问题讨论】:

  • 请注意,sed 将在提供的文件的 contents 上运行,而不是它们的名称。这就是为什么你的 sed 命令什么都不做的原因。
  • 请允许我给你一个标准的建议给新手:如果一个答案解决了你的问题,请点击它旁边的大复选标记 (✓) 接受它,也可以选择给它投票(up - 投票需要 15 个或更多声望点)。如果您发现其他答案有帮助,请给他们投票。接受(您将获得 2 个声望点)和投票有助于未来的读者。请参阅the relevant help-center article。如果您的问题尚未得到完全解答,请提供反馈或self-answer

标签: bash sed rename


【解决方案1】:

您可以在包含要重命名的文件的目录中执行以下操作:

for file_name in *.gz
do 
  new_file_name=$(sed 's/_[^.]*\./_/g' <<< "$file_name");
  mv "$file_name" "$new_file_name";
done

模式 (_[^.]*\.) 从第一个 _ 开始匹配,直到第一个 .(包括两者)。 [^.]* 表示 0 个或多个非点(或非句点)字符。

例子:

AMD$ ls
UTSHoS10_Other_CAAGCC-TTAGGA_R_160418.R1.fq.gz  UTSHoS12_Other_GGCAAG-TTAGGA_R_160418.R1.fq.gz
UTSHoS10_Other_CAAGCC-TTAGGA_R_160418.R2.fq.gz  UTSHoS12_Other_GGCAAG-TTAGGA_R_160418.R2.fq.gz
UTSHoS11_Other_AGGCCT-TTAGGA_R_160418.R2.fq.gz

AMD$ for file_name in *.gz
> do new_file_name=$(sed 's/_[^.]*\./_/g' <<< "$file_name")
> mv "$file_name" "$new_file_name"
> done

AMD$ ls
UTSHoS10_R1.fq.gz  UTSHoS10_R2.fq.gz  UTSHoS11_R2.fq.gz  UTSHoS12_R1.fq.gz  UTSHoS12_R2.fq.gz

【讨论】:

  • 谢谢,效果很好。我唯一不明白的是sed 命令中的这段代码_[^.]*\. 如何在我的文件名中指定模式...
  • 此模式从第一个 _ 开始匹配到第一个 .(包括两者)。 [^.]* 表示 0 个或多个非点(或非句点)字符
  • 我无法完成这项工作,它吐出:“没有这样的文件或目录”。这是我的代码:file_name=Screenshot_2020-08-06-16-13-43-731_com.tclhz.gallery.jpg new_file_name=$(sed 's/_[^.]*\./_/g'
【解决方案2】:

Parameter expansions in bash 可以基于类似 glob 的模式执行字符串替换,这比在每次循环迭代中调用额外的外部实用程序(例如 sed)提供了更有效的解决方案:

for f in *.gz; do echo mv "$f" "${f/_Other_*-TTAGGA_R_160418./_}"; done

删除mv 之前的echo 以执行实际重命名。

【讨论】:

    【解决方案3】:

    Pure Bash,使用子字符串操作并假设所有文件名具有相同的长度:

    for file in UTS*.gz; do
      echo mv -i "$file" "${file:0:9}${file:38:8}"
    done
    

    输出:

    mv -i UTSHoS10_Other_CAAGCC-TTAGGA_R_160418.R1.fq.gz UTSHoS10_R1.fq.gz
    mv -i UTSHoS10_Other_CAAGCC-TTAGGA_R_160418.R2.fq.gz UTSHoS10_R2.fq.gz
    mv -i UTSHoS11_Other_AGGCCT-TTAGGA_R_160418.R2.fq.gz UTSHoS11_R2.fq.gz
    mv -i UTSHoS11_Other_AGGCCT-TTAGGA_R_160418.R2.fq.gz UTSHoS11_R2.fq.gz
    mv -i UTSHoS12_Other_GGCAAG-TTAGGA_R_160418.R1.fq.gz UTSHoS12_R1.fq.gz
    mv -i UTSHoS12_Other_GGCAAG-TTAGGA_R_160418.R2.fq.gz UTSHoS12_R2.fq.gz
    

    验证后,从循环内的行中删除 echo 并再次运行。

    【讨论】:

      【解决方案4】:

      使用您的 sed 命令,这可以作为 bash 单线:

      for name in UTSH*fq.gz; do newname=$(echo $name | sed 's/_Other.*160418\./_/'); echo mv $name $newname; done
      

      注意事项:

      • 我已经调整了您的 sed 命令:它有一个 *,前面没有 .(sed 采用正则表达式,而不是通配符模式)。同样,点需要转义。
      • 为了查看它是否有效,而无需实际重命名文件,我将echo 命令留在了其中。很容易删除它以使其正常工作。
      • 显然,它不必是单行的。但有时,这会让您更轻松地编辑和浏览命令行历史记录。

      【讨论】:

      • 其他解决方案可以使用 bash 字符串替换,但是由于您使用 sed 标记了您的问题并且已经有了 sed 模式,所以我同意了。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-03
      • 1970-01-01
      • 1970-01-01
      • 2019-02-07
      • 2019-08-18
      相关资源
      最近更新 更多