Bash如何重命名一系列包以删除其版本号?我一直在玩expr
和%%
,但无济于事。
示例:
Xft2-2.1.13.pkg
变为Xft2.pkg
jasper-1.900.1.pkg
变为jasper.pkg
xorg-libXrandr-1.2.3.pkg
变为xorg-libXrandr.pkg
答案 0 :(得分:172)
您可以使用bash的参数扩展功能
for i in ./*.pkg ; do mv "$i" "${i/-[0-9.]*.pkg/.pkg}" ; done
带空格的文件名需要引号。
答案 1 :(得分:32)
如果所有文件都在序列
的同一目录中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 中,正则表达式分组序列的前面是反斜杠,\(
和\)
,而不是单括号(
和{{ 1}}。
答案 2 :(得分:10)
我会做这样的事情:
for file in *.pkg ; do
mv $file $(echo $file | rev | cut -f2- -d- | rev).pkg
done
假设您的所有文件都在当前目录中。如果没有,请尝试使用Javier上面建议的查找。
编辑:此外,此版本不会像上面的其他版本那样使用任何特定于bash的功能,这会让您获得更多便携性。
答案 3 :(得分:4)
这是一个近似等同于currently accepted answer的POSIX。这会将Bash-only ${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.]*
保留在接受的答案中,尽管这可能会产生误导。它不是正则表达式,而是一个glob模式;所以它并不意味着“破折号后跟零个或多个数字或点”。相反,它意味着“破折号,后跟数字或点,后跟任何东西”。 “任何事物”将是最短的匹配,而不是最长的匹配。 (Bash提供##
和%%
来修剪最长的前缀或后缀,而不是最短的。)
答案 4 :(得分:3)
更好地使用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
计算正则表达式是一个练习(就像处理包含空格的文件名一样)
答案 5 :(得分:3)
我们可以假设任何* nix都可以使用sed
,但我们无法确定
它支持sed -n
生成mv命令。 (注意:只有GNU sed
执行此操作。)
即便如此,bash builtins和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
由于mv
没有自动创建目标文件夹,我们无法使用
我们的初始版本sedrename
。
这是一个相当小的变化,所以包含该功能很不错:
自bash以来,我们需要一个效用函数abspath
(或绝对路径)
没有这个内置。
abspath () { case "$1" in
/*)printf "%s\n" "$1";;
*)printf "%s\n" "$PWD/$1";;
esac; }
一旦我们有了,我们可以为a生成目标文件夹 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"
这是完整的文件夹识别脚本...
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
}
当然,当我们没有特定的目标文件夹时,它仍然有效 太
如果我们想将所有歌曲放入文件夹./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
使用此脚本将文件夹从文件夹移动到单个文件夹中:
假设我们想收集所有匹配的文件,并放置它们 在当前文件夹中,我们可以这样做:
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模式规则适用于此脚本,这些模式不适用
PCRE(Perl兼容正则表达式)。你可以有sed
使用sed -r
或sed -E
扩展正则表达式语法
取决于您的平台。
有关完整说明,请参阅POSIX兼容man re_format
sed基本和扩展的正则表达式模式。
答案 6 :(得分:1)
这似乎可以假设
剥离.pkg,然后剥离 - ..
for x in $(ls); do echo $x $(echo $x | sed 's/\.pkg//g' | sed 's/-.*//g').pkg; done
答案 7 :(得分:1)
我在同一文件夹中将多个*.txt
个文件重命名为.sql
。
以下为我工作:
for i in \`ls *.txt | awk -F "." '{print $1}'\` ;do mv $i.txt $i.sql; done
答案 8 :(得分:0)
感谢您的回答。我也遇到了一些问题。将.nzb.queued文件移动到.nzb文件。它在文件名中有空格和其他副本,这解决了我的问题:
find . -type f -name "*.nzb.queued" |
sed -ne "s/^\(\(.*\).nzb.queued\)$/mv -v \"\1\" \"\2.nzb\"/p" |
sh
这是基于Diomidis Spinellis的答案。
正则表达式为整个文件名创建一个组,为.nzb.queued之前的部件创建一个组,然后创建一个shell移动命令。引用字符串。这也避免了在shell脚本中创建循环,因为这已经由sed。
完成