【问题标题】:How do change all filenames with a similar but not identical structure?如何更改具有相似但不相同结构的所有文件名?
【发布时间】:2017-01-21 05:53:46
【问题描述】:

由于必须使用手动复制和重命名文件的导入工具的组合来完成各种复杂的照片库迁移,我似乎最终得到了大量具有相似结构的文件。这是一个例子:

2009-05-05 - 2009-05-05 - IMG_0486 - 2009-05-05 at 10-13-43 - 4209 - 2009-05-05.JPG

应该是什么:

2009-05-05 - IMG_0486.jpg

其他文件结构相同,但显然个别日期和 IMG 编号不同。

有什么方法可以在终端中执行一些命令行魔术来自动将这些文件重命名为缩短/正确的版本?

【问题讨论】:

  • 文件名应该保留空格吗?

标签: bash macos shell file command-line


【解决方案1】:

我假设您可能有子目录并希望在此目录树中查找所有文件。

第一个代码块(您可以将其放入脚本中)是“安全的”(什么也不做),但会帮助您了解将要做什么。

datep="[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]"
dir="PUT_THE_FULL_PATH_OF_YOUR_MAIN_DIRECTORY"
while IFS= read -r file
do
  name="$(basename "$file")"
  [[ "$name" =~ ^($datep)\ -\ $datep\ -\ ([^[:space:]]+)\ -\ $datep.*[.](.+)$ ]] || continue
  date="${BASH_REMATCH[1]}"
  imgname="${BASH_REMATCH[2]}"
  ext="${BASH_REMATCH[3],,}"
  dir_of_file="$(dirname "$file")"
  target="$dir_of_file/$date - $imgname.$ext"
  echo "$file"
  echo "  would me moved to..."
  echo "    $target"
done < <(find "$dir" -type f)

确保输出是您想要和期望的。我无法对您的实际文件进行测试,如果此脚本没有产生完全令人满意的结果,我对拔毛不承担任何责任。如果您没有可靠且经过检查的备份,请不要盲目地让任何人(包括我)通过从互联网上复制和粘贴代码来弄乱您的宝贵数据。

一旦你确定了,决定你是否想尝试在没有任何测试机会的情况下编写某人的代码,并将以 echo 开头的连续三行替换为:

mv "$file" "$target"

请注意,文件名必须与非常严格的模式匹配才能考虑进行处理,因此如果您注意到某些文件未得到处理,则可能需要修改该模式。

【讨论】:

    【解决方案2】:

    假设它们都是完全相同相同的结构、空格和所有内容,您可以使用awk 将名称拆分为空格作为断点。这是一个快速而肮脏的例子:

    #!/bin/bash
    output=""
    
    for file in /path/to/files/*; do
        unset output #clear variable from previous loop
        output="$(echo $file | awk '{print $1}')" #Assign the first field to the output variable
        output="$output"" - " #Append with [space][dash][space]
        output="$output""$(echo $file | awk '{print $5}')" #Append with IMG_* field
        output="$output""." #Append with period
        #Use -F '.' to split by period, and $NF to grab the last field (to get the extension)
        output="$output""$(echo $file | awk -F '.' '{print $NF}')"
    done
    

    从那里,像mv /path/to/files/$file /path/to/files/$output 这样的东西作为文件循环中的最后一行将重命名文件。我会先将一些文件复制到另一个文件夹中进行测试,因为我们正在处理文件操作。

    所有的输出分配行也可以合并为一行,但不太容易阅读。

    output="$(echo $file | awk '{print $1 " - " $5 "."}')""$(echo $file | awk -F '.' '{print $NF}')"
    

    不过,您仍然需要一个文件循环。

    【讨论】:

      【解决方案3】:

      假设您要转换文件名与第一个日期和 IMG* 名称,您可以在文件夹上运行以下命令:

      IFS=$'\n'
      for file in *
      do
      printf "mv '$file' '"
      printf '%s' $(cut -d" " -f1,4,5 <<< "$file")
      printf "'.jpg"
      done | sh
      

      【讨论】:

      • 请参阅Why you shouldn't parse the output of ls(1),相应地编辑您的答案以避免被否决。这行不通
      • 正是出于这个原因,我添加了IFS=$'\n'。我在本地机器上试了一下,效果很好
      • 参考共享链接,还要注意 ls 有时会如何混淆您的文件名数据(在我们的例子中,它会将单词“a”和“newline”之间的换行符变成问号. 一些系统用 \n 代替。)。在某些系统上,当其输出不是终端时,它不会执行此操作,而在其他系统上,它总是会破坏文件名。总而言之,您真的不能也不应该相信 ls 的输出是您想要使用的文件名的真实表示。所以不要。,我不会投反对票,但这不是最有效的方式,请使用find
      猜你喜欢
      • 1970-01-01
      • 2022-10-17
      • 2023-03-15
      • 2016-09-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多