如何可以砸重命名的一系列软件包,以消除他们的版本数字?我一直在玩弄周围有两个 expr%%, ,也没有用。

实例:

Xft2-2.1.13.pkg 变得 Xft2.pkg

jasper-1.900.1.pkg 变得 jasper.pkg

xorg-libXrandr-1.2.3.pkg 变得 xorg-libXrandr.pkg

有帮助吗?

解决方案

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

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

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

其他提示

如果所有文件都在序列

的同一目录中
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 中,正则表达式分组序列的前面是反斜杠, \( \),而不是单个括号

我会做这样的事情:

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

假设您的所有文件都在当前目录中。如果没有,请尝试使用Javier上面建议的查找。

编辑:此外,此版本不会像上面的其他版本那样使用任何特定于bash的功能,这会让您获得更多便携性。

这是一个与目前接受的答案相近的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提供 ## %% 来修剪最长的前缀或后缀,而不是最短的。)

更好地使用 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

计算正则表达式是一个练习(就像处理包含空格的文件名一样)

我们可以假设 sed 可用于任何* nix,但我们无法确定 它将支持 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: 
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
sed_pattern files..." fi }

用法

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

创建目标文件夹:

由于 mv 不会自动创建我们无法使用的目标文件夹 我们的初始版本的 sedrename

这是一个相当小的变化,所以包含该功能很好:

自bash以来,我们需要一个实用函数, abspath (或绝对路径) 没有这个内置。

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

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

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

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: 
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
sed_pattern files..." fi }

这是完整的文件夹识别脚本......

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

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

如果我们想将所有歌曲放入文件夹, ./ Beethoven / ,我们可以这样做:

用法

<*>

奖金回合......

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

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

<*>

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

常规sed模式规则适用于此脚本,但这些模式不适用 PCRE(Perl兼容正则表达式)。你可以有sed 扩展正则表达式语法,使用 sed -r sed -E 取决于您的平台。

有关完整说明,请参阅符合POSIX的 man re_format sed基本和扩展的正则表达式模式。

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

对于你的例子,我会这样做:

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

's'意味着替代。表单是s / searchPattern / replacement / files_to_apply。你需要使用正则表达式,这需要一些研究,但这是值得的努力。

这似乎是工作假设

  • 一切都结束美元包
  • 你的版本#'s总是开始一个"-"

脱掉。包,然后脱掉-..

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

我在同一文件夹中将多个 * .txt 文件重命名为 .sql 。 以下为我工作:

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

感谢您的回答。我也遇到了一些问题。将.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。

完成
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top