【问题标题】:How can I create a rename script using multiple rules?如何使用多个规则创建重命名脚本?
【发布时间】:2019-12-13 14:57:47
【问题描述】:

我经常将一堆名为“Unknown.png”的文件放入一个文件夹,并且经常将它们重命名为“unknown (1).png、unknown (2).png”等。这有点问题有时在清理文件并将它们移动到其他地方时,我会被问到是否要替换或重命名等。

所以我决定创建一个 crontab 任务,将文件重命名为 CB_RANDOM,这样我什至不必担心可能会覆盖两个同名文件。

到目前为止,我能想到,我找到了文件,将名称 Unknown 替换为 CB_ 并添加一个随机数。

问题出现在文件名末尾的 (x) 处。我也设法弄清楚了如何解决它,我只是去掉了所有括号和数字。

问题是我不知道如何使重命名函数遵循这两个规则。

for u in (find -name unknown*); do 
    rCode = random
    rename -v 's/unknown/CB_$rCode' $u 
    rename -v 's/[ ()0123456789]//g' $u

理想情况下,我希望能够在同一行代码上遵循这两个规则,特别是因为一旦它运行第一行,那么 $u 将无法找到第二步的文件。

【问题讨论】:

  • 重命名整个文件名而不是 unknown 部分可以解决这个问题。 rename -v "${u}" "CB_${rCode}.png" "${u}"
  • 由于您使用的是循环,您可以简单地使用bash 语法构造新名称并使用mv。如果您想使用模式规则重命名文件文件夹,那么rename 是要使用的工具。

标签: bash rename


【解决方案1】:

不需要循环:

find -name 'unknown*' -exec rename 's/unknown \([0-9]+\)\.(.*)$/"CB_".sprintf("%04s",int(rand(10000))).".".$1/e' {} \;
  • find所有文件,从当前目录开始,递归,名称类似于“unknown (1).png”
  • rename 生成的文件名类似于“CB_0135.png”

如果文件名已经存在,则会产生错误消息。

【讨论】:

  • 哦,这是一个不错的命令,但它仅在我在末尾添加文件名时才有效,它似乎并没有为找到的每个文件运行重命名命令。知道我们该如何解决这个问题吗?
  • @DaniloReyes:恐怕我没有听懂你的意思。此命令查找所有以“未知”开头的文件,然后如果匹配模式(括号中有数字)并具有任何扩展名,则重命名它们。图案当然可以改变。但是在最后添加一个文件名根本不应该做任何事情或应该产生错误。该命令按原样适用于我。你修改了吗?如果是这样,怎么做?你的操作系统是什么?
  • 我使用的是 Ubuntu,如果我将代码按原样粘贴到终端上,它不会重命名任何文件。就我个人而言,即使在其他发行版中,我也一直在努力使 find -exec 命令工作。基本上我让它工作的方式是删除查找部分并在最后手动添加文件名。如果我删除 -exec 部分,它似乎实际上列出了所有文件。但是这两个命令不会以某种方式一起工作。尝试将它放在一个循环中并将文件通过它提供给你给我的重命名行,但它要么在文件名中添加一个 ./ 要么在 (x) 处裁剪它
  • 在玩弄了一大堆代码之后,试图完全理解每个部分的工作原理,我想出了如何让它工作我只需要从 s/^unknown 中删除 ^ 然后它重命名为 any unknown (x).png 文件,对于原始的 unknown.png 文件,我可以修改现有代码使其工作,我认为这一切都很好!太感谢了!我很好奇 ^ 是什么意思?因为如果我单独使用 rename 命令但在 find 命令中使用它时却失败了,我觉得它很奇怪。
  • @DaniloReyes:啊!对于那个很抱歉!插入符号 (^) 将正则表达式锚定在字符串的开头,但我没有考虑到 find 在其输出中包含文件路径这一事实。在这种情况下,它是当前目录 (./)。我将从我的答案中删除插入符号。但是请注意,如果没有它,名称为“完全未知 (1).png”的文件将匹配并被重命名。可以使用斜线作为锚点,我可以添加一个替代方案来显示这一点。
【解决方案2】:

你的代码应该先改成

# find is a subcommand, use $()
# find a file with wildcard, use quotes
for u in $(find -name "unknown*"); do 
    # Is random a command? Use $()
    rCode=$(random) 
    # Debug with echo, will show other problem
    echo "File $u"
    # $rCode will not be replaced by its value in single quotes
    # Write a filename in double quotes, so it will not be split by a space
    rename -v "s/unknown/CB_$rCode" "$u"
    rename -v 's/[ ()0123456789]//g' "$u"
done

带有echo 的新行表明循环正在分解空格处的文件名。你可以改变这个

while IFS= read -r u; do 
    # Use unique timestamp, not random value
    rCode=$(date '+%Y%m%d_%H%M') 
    echo "File $u"
    rename -v "s/unknown/CB_$rCode" "$u"
    rename -v 's/[ ()0123456789]//g' "$u"
done < <(find -name "unknown*")

我从不使用rename,并且会使用

while IFS= read -r u; do 
    # Use unique timestamp, not random value
    rCode=$(date '+%Y%m%d_%H%M') 
    # construct new filename. 
    # Restriction: Path to file is without newlines, spaces or parentheses
    newfile=$(sed 's/[ ()]//g; s/.*unknown/&_'"${rCode}"'_/' <<< "$u")
    echo "Moving file $u to ${newfile}"
    mv "$u" to "${newfile}"
done < <(find -name "unknown*")

编辑:
我删除了一个 sed 命令,用于重命名包含 (something) 的文件:

# Removed command
    newfile=$(sed 's/\(.*\)(\(.*\))/\1'"${rCode}"'_\2/' <<< "$u")

【讨论】:

  • 非常感谢您提供如此详细的回复,我一直在研究代码以了解每一行的作用(对不起,我对此有点新,但我正在尝试!所以首先我会注意到您将 FOR 循环替换为 WHILE 循环并在最后添加了 find 命令,这是否仍然使其仅将这些更改应用于名为 unknown* 的文件?似乎不起作用的部分代码正在剥离 (x)因为我得到类似于未知 193145_x.png 的文件名,它也不适用于仅 unknown.png 文件,看起来它需要文件在文件名上有一个 (x) 才能工作
  • 我编辑了我的答案,但您应该更喜欢@DennisWilliamson 的解决方案。 (我将 FOR 替换为 WHILE 用于带有空格的文件名,并将 find 移动到末尾,使其在没有附加子外壳的情况下运行。此处不相关,但在循环完成时,在子外壳中的循环中设置的变量将丢失)
猜你喜欢
  • 2021-04-10
  • 2011-03-09
  • 2017-11-26
  • 2021-11-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-14
  • 2016-09-12
相关资源
最近更新 更多