重命名多个目录中的文件名

重命名多个目录中的文件名

我有几个目录的文件顺序不正确,因为标题显示在文件编号之前。我想匹配并替换所有文件的末尾,减去扩展名,因此数字位于开头,如下所示。

由此;

A guide to perfect eggs-456704.mp4
Boil an egg-456702.mp4
How to ruin scrambled eggs-456703.mp4
Make green eggs and ham-456701.mp4
Poached eggs-456705.mp4

对此:

456701-Make green eggs and ham.mp4
456702-Boil an egg.mp4
456703-How to ruin scrambled eggs.mp4
456704-A guide to perfect eggs.mp4
456705-Poached eggs.mp4

每个带有空格的文件的标题长度是随机的,数字是“.mp4”扩展名之前的 6 位数字,但标题后面有一个破折号。

答案1

使用findShell (Bash, ksh, ksh93, mksh, zsh) Pattern substitution expansion

find * -type f -name "*.mp4" -exec bash -c 'echo mv -v "$1" "${1//[^0-9]}-${1//[\-0-9]}"' _ '{}' \;
  • 我们${1//[^0-9]}正在删除除数字之外的所有内容;是//全局替换语法,而/is 仅用于数字的第一次出现。

  • 然后是破折号/连字符-${1//[\-0-9]}我们将删除所有属于 a-或数字的内容(再次假设-文件名中只有一个和数字部分)。

我们-exec在上面使用的命令由于某些原因不安全1,2在这里,因为使用 Shell Substitution Expansion 它将采用文件的路径并导致意外的重命名+它将删除-文件名中的所有破折号!

最后,不要忘记删除echo命令中的上述内容,以在用于空运行的位置进行实际重命名。


find . -type f -name "*.mp4" -execdir sh -c '
    n="${1##*-}";fn="${1%-*}"; 
    echo mv -v "$1" "${n%.*}-${fn##*/}.mp4" ' _ '{}' \;

与之前的命令相同,但这里我们使用shell (POSIX sh/bash/Korn/zsh) parameter substitution expansion这将使-文件名中的所有破折号保持不变(如果有的话),a file-with -- here-006.file除了最后一个应该删除的破折号。

我们正在寻找仅以和-type f结尾的文件,即将当前目录更改为.mp4-execdirfind文件找到然后在该目录本身内执行 sh -c ' ... ' 。

  • 使用n="${1##*-}"“cut-up-to-last-prefix”:我们删除从文件名开始到最后看到的破折号-及其-本身的所有内容,并将其分配给变量n; or$1是返回到当前目录${1}的相对路径。./fileName-execdir sh -c '...' _ '{}' \;

  • 使用fn="${1%-*}"“cut-up-to-first-suffix”:我们将从文件名末尾删除所有内容,直到-看到第一个破折号及其-本身,并将其分配给变量fn

    现在n="456704.mp4"nf="./A guide to perfect eggs"假设第一个文件)。然后;

  • 我们将从${n%.*}-fileName 末尾删除所有内容,直到.看到第一个点及其.本身,然后添加破折号-。所以这只会产生 fileName 的数字部分456704

  • 我们${fn##*/}.mp4正在删除从文件名的请求到/看到最后一个斜杠及其/本身的所有内容,然后添加.mp4到末尾。所以才会出现这样的结果A guide to perfect eggs.mp4


1 使用中存在哪些安全问题和竞争条件find -exec
2 为什么使用“-execdir”操作对于 PATH 中的目录不安全?

答案2

这里有一种方法可以做到这一点。未经测试

#!/bin/bash

files=(*file)

for f in "${files[@]}" 
  do 
     get_ext="${f##*.}"
     no_ext="${f%-*}"
     n="${f##*-}" nn="${n%.*}"
     mv "$f" "$nn-$no_ext.$get_ext"
 done

答案3

set "a file blah blah-004.file" \
"b file blah blah blah-002.file" \
"c file blahh blah-003.file" \
"d file blah blah blah blabby blah-001.file" \
"e file blah-005.file"

for name; do
  old=$name                 # save old name
  ext=${name##*.}           # take extension
  name=${name%.*}           # remove extension
  number=${name##*-}        # take number
  name=${name%-*}           # remove number
  new="$number-$name.$ext"  # set new name
  echo mv "$old" "$new"     # test rename
done

echo如果有效的话,删除最后一个。

答案4

这是一个可移植的sh实现。

find . -name "*[0-9].mp4" |
    sed "s/\(.*\/\)\(.*\)-\([0-9]*\)\.mp4/'\1\2-\3.mp4' '\1\3-\2.mp4'/" |
    xargs -p -L 1 mv -v

find命令非常简单:它将仅返回.mp4扩展名前至少包含一位数字的文件。

sed命令复制文件名,用单引号将每个文件名引起来,然后第二个文件名将数字部分相应地在相对文件路径和文件名之间移动(例如,'./a/Boil an egg-456707' './a/456707-Boil an egg.mp4')。

然后将生成的当前文件名和新文件名列表传递给xargs命令,该命令将执行mv -v.-L 1需要该选项以便xarg一次处理一行。您可以-p从此命令中删除该选项并更改应使用的选项mv

我在 Ubuntu bash、 Mac OS High Sierra和shMac OS High Sierra上使用您的文件列表测试了此实现,将文件放置在不同的子目录中并添加了一些不合格的文件。bashsh

相关内容