使用 Bash 批处理重命名文件

Bash 如何重命名一系列包以删除它们的版本号?我一直在玩弄 expr%%,但没有用。

例子:

Xft2-2.1.13.pkg变成 Xft2.pkg

jasper-1.900.1.pkg becomes jasper.pkg

xorg-libXrandr-1.2.3.pkg变成 xorg-libXrandr.pkg

108180 次浏览

最好使用 sed,比如:

find . -type f -name "*.pkg" |
sed -e 's/((.*)-[0-9.]*\.pkg)/\1 \2.pkg/g' |
while read nameA nameB; do
mv $nameA $nameB;
done

计算正则表达式留作练习(处理包含空格的文件名也是如此)

这似乎工作,假设

  • 一切都以 $pkg 结束
  • 你的版本 # 总是以“-”开头

脱掉.pkg,然后脱掉-。

for x in $(ls); do echo $x $(echo $x | sed 's/\.pkg//g' | sed 's/-.*//g').pkg; done

您可以使用 bash 的参数扩展特性

for i in ./*.pkg ; do mv "$i" "${i/-[0-9.]*.pkg/.pkg}" ; done

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

我会这样做:

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

假设你所有的文件都在工作目录里,如果没有,试着按照上面哈维尔的建议使用 find。

编辑 : 此外,这个版本不使用任何特定于 bash 的特性,正如上面的其他版本一样,这将使您具有更强的可移植性。

如果所有文件都在同一个目录中,则序列

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

会做好你的工作。sed命令将创建一系列 mv命令,然后您可以将这些命令导入 shell。最好首先运行管道,不要使用后面的 | sh,以便验证命令是否满足您的要求。

要遍历多个目录,可以使用

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

请注意,在 Sed中,正则表达式分组序列是括号,前面是反斜杠,\(\),而不是单括号 ()

谢谢你的回答。我也遇到了一些问题。行动。将文件排队到。NZB 文件。它在文件名中有空格和其他残渣,这解决了我的问题:

find . -type f -name "*.nzb.queued" |
sed -ne "s/^\(\(.*\).nzb.queued\)$/mv -v \"\1\" \"\2.nzb\"/p" |
sh

这是基于 Diomidis Spinellis 的答案。

正则表达式为整个文件名创建一个组,为之前的部分创建一个组。排队,然后创建一个 shell move 命令。引用字符串。这也避免了在 shell 脚本中创建循环,因为 sed 已经这样做了。

我有多个 *.txt文件被重命名为 .sql在同一个文件夹。 below worked for me:

for i in \`ls *.txt | awk -F "." '{print $1}'\` ;do mv $i.txt $i.sql; done

下面是一个 POSIX 近似于 currently accepted answer。这样就把仅 Bash 的 ${variable/substring/replacement}参数扩展换成了在任何与 Bourne 兼容的 shell 中都可用的参数扩展。

for i in ./*.pkg; do
mv "$i" "${i%-[0-9.]*.pkg}.pkg"
done

参数扩展 ${variable%pattern}产生 variable的值,其中任何后缀与去掉的 pattern相匹配。(还有一个 ${variable#pattern}来删除前缀。)

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

我们可以假设 sed在任何 * nix 上都可用,但是我们不能确定 它将支持 sed -n生成 mv 命令

即便如此,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
}

用法

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

Creating target folders:

因为 mv不会自动创建我们不能使用的目标文件夹 我们 sedrename的初始版本。

It's a fairly small change, so it'd be nice to include that feature:

从 bash 开始,我们需要一个实用函数 abspath(或绝对路径) 没有这样的内置。

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

一旦我们有了它,我们就可以为 Sed/重命名模式,包括新的文件夹结构。

This will ensure we know the names of our target folders. When we 我们需要在目标文件名上使用它。

# 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"

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

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
}

当然,如果我们没有特定的目标文件夹,它仍然可以工作 也是。

If we wanted to put all the songs into a folder, ./Beethoven/ we can do this:

用法

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

额外奖励。

Using this script to move files from folders into a single folder:

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

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

关于 sed 正则表达式模式的注释

Regular sed pattern rules apply in this script, these patterns aren't PCRE (Perl 兼容正则表达式) 扩展的正则表达式语法,使用 sed -rsed -E 取决于你的平台。

有关。的完整描述,请参阅符合 POSIX 的 man re_format Sed 基本和扩展的 regexp 模式。

我发现用于这类事情的重命名工具要简单得多。我在 OSX 的自制软件上找到的

举个例子:

rename 's/\d*?\.\d*?\.\d*?//' *.pkg

“ s”表示替代品。这个表单是 s/searchPattern/place/files _ to _ application。您需要使用正则表达式来完成这个任务,这需要进行一些研究,但是非常值得。