使用Bash批量重命名文件

Jer*_*y L 96 bash shell file-rename

Bash如何重命名一系列包以删除其版本号?我一直在玩弄周围既expr%%,都无济于事.

例子:

Xft2-2.1.13.pkgXft2.pkg

jasper-1.900.1.pkgjasper.pkg

xorg-libXrandr-1.2.3.pkgxorg-libXrandr.pkg

ric*_*chq 180

您可以使用bash的参数扩展功能

for i in ./*.pkg ; do mv "$i" "${i/-[0-9.]*.pkg/.pkg}" ; done
Run Code Online (Sandbox Code Playgroud)

带空格的文件名需要引号.

  • 如果有人能解释“${i/-[0-9.]*.pkg/.pkg}”行话的作用,那就太好了。否则,这个答案对于其他没有与OP完全相同需求的人来说没有什么帮助。 (3认同)
  • 到目前为止,我最喜欢这个! (2认同)
  • 我也喜欢它,但它使用 bash 特定的功能...我通常不会使用它们而支持“标准”sh。 (2认同)
  • 对于一次性的单线交互式东西,我总是使用它而不是sed-fu.如果它是一个脚本,那么,请避免使用bashisms. (2认同)
  • 不是bash解决方案,但如果你安装了perl,它为批量重命名提供了方便的重命名命令,只需"重命名"s/ - [0-9.]*//"*.pkg` (2认同)
  • 我可以在“{i/-[0-9.]*.pkg/.pkg}”中查找替换业务详细信息的技术术语/手册页是什么? (2认同)

Dio*_*lis 32

如果所有文件都在同一目录中的顺序

ls | 
sed -n 's/\(.*\)\(-[0-9.]*\.pkg\)/mv "\1\2" "\1.pkg"/p' | 
sh
Run Code Online (Sandbox Code Playgroud)

会做你的工作.的sed的命令将创建的序列MV命令,这些命令可以然后管进入外壳.最好先运行没有尾随的管道| sh,以验证命令是否符合要求.

要通过多个目录进行递归,请使用类似的东西

find . -type f |
sed -n 's/\(.*\)\(-[0-9.]*\.pkg\)/mv "\1\2" "\1.pkg"/p' |
sh
Run Code Online (Sandbox Code Playgroud)

注意,在sed的正则表达式分组序列是通过一个反斜杠支架, \(\),而不是单一的括号().

  • 在sed中,正则表达式分组序列是\(而不是单个括号. (2认同)

Die*_*lla 10

我会做这样的事情:

for file in *.pkg ; do
    mv $file $(echo $file | rev | cut -f2- -d- | rev).pkg
done
Run Code Online (Sandbox Code Playgroud)

假设您的所有文件都在当前目录中.如果没有,请尝试使用Javier上面提到的find.

编辑:此外,此版本不使用任何特定于bash的功能,如上面的其他功能,这将导致您更具可移植性.


tri*_*eee 6

这是当前接受的答案的 POSIX 近等价。这将 Bash-only${variable/substring/replacement}参数扩展交换为在任何 Bourne 兼容 shell 中可用的参数扩展。

for i in ./*.pkg; do
    mv "$i" "${i%-[0-9.]*.pkg}.pkg"
done
Run Code Online (Sandbox Code Playgroud)

参数扩展${variable%pattern}产生的值variablepattern删除匹配的任何后缀。(还有${variable#pattern}删除前缀。)

我保留了-[0-9.]*接受答案中的子模式,尽管它可能会产生误导。它不是一个正则表达式,而是一个 glob 模式;所以它并不意味着“破折号后跟零个或多个数字或点”。相反,它的意思是“一个破折号,后跟一个数字或一个点,后跟任何东西”。“任何”将是最短的匹配项,而不是最长的匹配项。(Bash 提供##%%修剪尽可能长的前缀或后缀,而不是最短的。)


oco*_*odo 5

我们可以假设sed在任何 *nix 上都可用,但我们不能确定它是否支持sed -n生成 mv 命令。(注意:只有 GNU 会这样做sed。)

即便如此,使用 bash 内置函数和 sed,我们可以快速创建一个 shell 函数来执行此操作。

sedrename() {
  if [ $# -gt 1 ]; then
    sed_pattern=$1
    shift
    for file in $(ls $@); do
      mv -v "$file" "$(sed $sed_pattern <<< $file)"
    done
  else
    echo "usage: $0 sed_pattern files..."
  fi
}
Run Code Online (Sandbox Code Playgroud)

用法

sedrename 's|\(.*\)\(-[0-9.]*\.pkg\)|\1\2|' *.pkg

before:

./Xft2-2.1.13.pkg
./jasper-1.900.1.pkg
./xorg-libXrandr-1.2.3.pkg

after:

./Xft2.pkg
./jasper.pkg
./xorg-libXrandr.pkg
Run Code Online (Sandbox Code Playgroud)

创建目标文件夹:

由于mv不会自动创建目标文件夹,因此我们无法使用sedrename.

这是一个相当小的变化,因此包含该功能会很好:

我们需要一个实用程序函数abspath(或绝对路径),因为 bash 没有这个内置函数。

abspath () { case "$1" in
               /*)printf "%s\n" "$1";;
               *)printf "%s\n" "$PWD/$1";;
             esac; }
Run Code Online (Sandbox Code Playgroud)

一旦我们有了它,我们就可以为包含新文件夹结构的 sed/rename 模式生成目标文件夹。

这将确保我们知道目标文件夹的名称。当我们重命名时,我们需要在目标文件名上使用它。

# generate the rename target
target="$(sed $sed_pattern <<< $file)"

# Use absolute path of the rename target to make target folder structure
mkdir -p "$(dirname $(abspath $target))"

# finally move the file to the target name/folders
mv -v "$file" "$target"
Run Code Online (Sandbox Code Playgroud)

这是完整的文件夹感知脚本......

sedrename() {
  if [ $# -gt 1 ]; then
    sed_pattern=$1
    shift
    for file in $(ls $@); do
      target="$(sed $sed_pattern <<< $file)"
      mkdir -p "$(dirname $(abspath $target))"
      mv -v "$file" "$target"
    done
  else
    echo "usage: $0 sed_pattern files..."
  fi
}
Run Code Online (Sandbox Code Playgroud)

当然,当我们也没有特定的目标文件夹时,它仍然有效。

如果我们想把所有的歌曲放到一个文件夹中,./Beethoven/我们可以这样做:

用法

sedrename 's|Beethoven - |Beethoven/|g' *.mp3

before:

./Beethoven - Fur Elise.mp3
./Beethoven - Moonlight Sonata.mp3
./Beethoven - Ode to Joy.mp3
./Beethoven - Rage Over the Lost Penny.mp3

after:

./Beethoven/Fur Elise.mp3
./Beethoven/Moonlight Sonata.mp3
./Beethoven/Ode to Joy.mp3
./Beethoven/Rage Over the Lost Penny.mp3
Run Code Online (Sandbox Code Playgroud)

奖金回合...

使用此脚本将文件从文件夹移动到单个文件夹:

假设我们想收集所有匹配的文件,并将它们放在当前文件夹中,我们可以这样做:

sedrename 's|.*/||' **/*.mp3

before:

./Beethoven/Fur Elise.mp3
./Beethoven/Moonlight Sonata.mp3
./Beethoven/Ode to Joy.mp3
./Beethoven/Rage Over the Lost Penny.mp3

after:

./Beethoven/ # (now empty)
./Fur Elise.mp3
./Moonlight Sonata.mp3
./Ode to Joy.mp3
./Rage Over the Lost Penny.mp3
Run Code Online (Sandbox Code Playgroud)

关于 sed 正则表达式模式的注意事项

正则 sed 模式规则适用于此脚本,这些模式不是 PCRE(Perl 兼容正则表达式)。您可以使用 sed 扩展正则表达式语法,sed -r或者sed -E 根据您的平台使用。

有关man re_formatsed 基本和扩展正则表达式模式的完整描述,请参阅 POSIX 兼容。


小智 5

我发现重命名是用于此类事情的更直接的工具。我在 OSX 的 Homebrew 上找到了它

对于您的示例,我会这样做:

rename 's/\d*?\.\d*?\.\d*?//' *.pkg
Run Code Online (Sandbox Code Playgroud)

“s”表示替代。格式为 s/searchPattern/replacement/files_to_apply。您需要为此使用正则表达式,这需要一些研究,但值得付出努力。