Batch renaming files with Bash

2019-01-03 07:55发布

How can Bash rename a series of packages to remove their version numbers? I've been toying around with both expr and %%, to no avail.

Examples:

Xft2-2.1.13.pkg becomes Xft2.pkg

jasper-1.900.1.pkg becomes jasper.pkg

xorg-libXrandr-1.2.3.pkg becomes xorg-libXrandr.pkg

10条回答
可以哭但决不认输i
2楼-- · 2019-01-03 08:38

You could use bash's parameter expansion feature

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

Quotes are needed for filenames with spaces.

查看更多
我欲成王,谁敢阻挡
3楼-- · 2019-01-03 08:39

I'll do something like this:

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

supposed all your file are in the current directory. If not, try to use find as advised above by Javier.

EDIT: Also, this version don't use any bash-specific features, as others above, which leads you to more portability.

查看更多
祖国的老花朵
4楼-- · 2019-01-03 08:43

If all files are in the same directory the sequence

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

will do your job. The sed command will create a sequence of mv commands, which you can then pipe into the shell. It's best to first run the pipeline without the trailing | sh so as to verify that the command does what you want.

To recurse through multiple directories use something like

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

Note that in sed the regular expression grouping sequence is brackets preceded by a backslash, \( and \), rather than single brackets ( and ).

查看更多
Ridiculous、
5楼-- · 2019-01-03 08:44

Here is a POSIX near-equivalent of the currently accepted answer. This trades the Bash-only ${variable/substring/replacement} parameter expansion for one which is available in any Bourne-compatible shell.

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

The parameter expansion ${variable%pattern} produces the value of variable with any suffix which matches pattern removed. (There is also ${variable#pattern} to remove a prefix.)

I kept the subpattern -[0-9.]* from the accepted answer although it is perhaps misleading. It's not a regular expression, but a glob pattern; so it doesn't mean "a dash followed by zero or more numbers or dots". Instead, it means "a dash, followed by a number or a dot, followed by anything". The "anything" will be the shortest possible match, not the longest. (Bash offers ## and %% for trimming the longest possible prefix or suffix, rather than the shortest.)

查看更多
何必那么认真
6楼-- · 2019-01-03 08:46

I had multiple *.txt files to be renamed as .sql in same folder. below worked for me:

for i in \`ls *.txt | awk -F "." '{print $1}'\` ;do mv $i.txt $i.sql; done
查看更多
Summer. ? 凉城
7楼-- · 2019-01-03 08:47

I find that rename is a much more straightforward tool to use for this sort of thing. I found it on Homebrew for OSX

For your example I would do:

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

The 's' means substitute. The form is s/searchPattern/replacement/ files_to_apply. You need to use regex for this which takes a little study but it's well worth the effort.

查看更多
登录 后发表回答