【问题标题】:rename folder by changing the order通过更改顺序重命名文件夹
【发布时间】:2019-04-19 00:19:18
【问题描述】:

我有几个目录,名称如下:

"Some NameAndMorEyy_mm_dd"

我想将它们重命名为:

"yy_mm_dd_Some NameAndMore"

其中,Some NameAndMore 部分可以包含重音符号、空格,并且可以以空格或_ 或两者结尾,这些都需要删除。

一些例子:

"Jhon Doe_18_08_02"
"Jhon Doe 18_08_03"
"Jhon Doe_ 18_08_04"
"Jhon Doe _18_07_02"
"Jhon Doé_18_10_02"
"Jhon Doñe_18_08_02"

应该重命名为:

"18_08_02_Jhon Doe"
"18_08_03_Jhon Doe"
"18_08_04_Jhon Doe"
"18_07_02_Jhon Doe"
"18_10_02_Jhon Doé"
"18_08_02_Jhon Doñe"

分别。

现在,同时以空格和_ 结尾的只是少数,所以如果你愿意,可以忽略它们。

【问题讨论】:

  • 您能否分享更多适合不同场景的示例以及您想将它们重命名为什么。文件名是否总是以yy_mm_dd 结尾,这样很容易挑出那部分?
  • 完成,查看更新的问题
  • 有很多在 SO 上使用 rename 的示例,只需搜索 [rename] 即可找到标记为此类的示例。 stackoverflow.com/a/51641543/2836621

标签: bash rename


【解决方案1】:

这(mv 除外)是一个纯 Bash 解决方案:

#! /bin/bash

shopt -s dotglob    # Globs match names beginning with '.'
shopt -s nullglob   # Globs expand to nothing when nothing matches

for namedate in *[0-9][0-9]_[0-9][0-9]_[0-9][0-9] ; do
    [[ -d $namedate ]] || continue  # Skip non-directories
    name=${namedate%??_??_??}       # Remove date from end to get name
    date=${namedate#"$name"}        # Remove name from start to get date
    name=${name%[ _]}               # Remove trailing space or _
    name=${name%[ _]}               # Remove possible 2nd trailing space or _
    datename=${date}_${name}

    if [[ -e $datename ]] ; then
        printf "Warning: '%s' already exists.  Skipping.\\n" "$datename" >&2
    else
        mv -- "$namedate" "$datename"
        printf "Moved '%s' to '%s'\\n" "$namedate" "$datename" >&2
    fi
done

代码是Shellcheck-clean。为了避免做一些奇怪的事情,它会在执行mv 之前检查目标目录是否不存在。

【讨论】:

    【解决方案2】:

    还有一个懒惰的衬垫 :) ... 去除第一个回声以使其工作

    for i in *; do  [[ -d $i ]] && echo mv "$i" "$( echo $i| sed -r -e 's/^(.+)([0-9][0-9]_[0-9][0-9]_[0-9][0-9])$/\2_\1/' -e 's/[_ ]+$//' )" ; done
    mv Jhon Doe _18_07_02 18_07_02_Jhon Doe
    mv Jhon Doe_18_08_02 18_08_02_Jhon Doe
    mv Jhon Doe 18_08_03 18_08_03_Jhon Doe
    mv Jhon Doe_ 18_08_04 18_08_04_Jhon Doe
    mv Jhon Doé_18_10_02 18_10_02_Jhon Doé
    mv Jhon Doñe_18_08_02 18_08_02_Jhon Doñ
    

    【讨论】:

    • 不错。我只是想评论一下把最后 8 个字符去掉并使用它们。
    • 请注意,如果任何文件名以 - 开头,这将是错误的。要解决这个问题,您需要在 mv 的参数前面加上 ./,或者添加一个 -- 参数。此外,它还会破坏任何与 OP 格式不匹配的文件名。要解决这个问题,您需要使用限制性更强的 fileglob,例如 *[_\ ][0-9][0-9]_[0-9][0-9]_[0-9][0-9]
    • @ruakh,你能用你的建议展示解决方案吗?因为确实这个解决方案也重命名了其他东西。以及如何使它只重命名目录?
    • @kurokirasama - 你提供一个更大的样本怎么样?修改它只做日期是微不足道的。
    • @kurokirasama:我愿意,但 pjh 以非常全面的答案击败了我,几乎无法改进。
    【解决方案3】:

    这是一个有点慢的解决方案,但它应该可以工作。将echo "move ..." 替换为实际的移动命令。它可以通过使用更少的子shell 来加速sed

    这个想法是通过找到数字的开头来找到拆分。这假设名称中没有任何数字。我们分成两部分,并从名称中删除任何 _ 或空格,然后在移动中重新组合在一起。

    同样使用find,这样带空格的文件也能得到妥善处理。

    #!/bin/bash
    
    find . -mindepth 1 -maxdepth 1 -type d | (while read -r d; do
      d=$(basename "$d")
      name_part=$(echo "$d" | sed -rn 's/(^[^0-9]+)(.*)$/\1/p')
      date_part=$(echo "$d" | sed -rn 's/(^[^0-9]+)(.*)$/\2/p')
    
      name_part=$(echo "$name_part" | sed -rn 's/([_ ]+)$//p')
    
      # change this line here
      # mv "$d" "${date_part}_${name_part}"
      echo "move $d ==> ${date_part}_${name_part}"
    done)
    

    从测试数据来看,输出显示:

    move Jhon Doe_18_08_02 ==> 18_08_02_Jhon Doe
    move Jhon Doe 18_08_03 ==> 18_08_03_Jhon Doe
    move Jhon Doe_ 18_08_04 ==> 18_08_04_Jhon Doe
    move Jhon Doñe_18_08_02 ==> 18_08_02_Jhon Doñe
    move Jhon Doé_18_10_02 ==> 18_10_02_Jhon Doé
    

    【讨论】:

      猜你喜欢
      • 2021-12-27
      • 2021-02-27
      • 2014-08-23
      • 1970-01-01
      • 2011-05-23
      • 2011-07-22
      • 2017-04-10
      • 1970-01-01
      • 2013-07-17
      相关资源
      最近更新 更多