views:

877

answers:

5

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

A: 

better use sed for this, something like:

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

figuring up the regular expression is left as an exercise (as is dealing with filenames that include spaces)

Javier
Thanks: Spaces are not used in the names.
Nerdling
A: 

This seems to work assuming that

  • everything ends with $pkg
  • your version #'s always start with a "-"

strip off the .pkg, then strip off -..

for x in $(ls); do echo $x $(echo $x | sed 's/\.pkg//g' | sed 's/-.*//g').pkg; done
Steve B.
There are some packages that have a hyphen in their name (see third example). Does this impact your code?
Nerdling
+6  A: 

You could use bash's parameter expansion feature

for i in *.pkg ; do mv $i ${i/-[0-9.]*.pkg/.pkg} ; done
rq
I like this the best so far!
Nerdling
I like it too, but it uses bash-specific features... I normally don't use them in favor of "standard" sh.
Diego Sevilla
For throwaway one-line interactive stuff I always use this instead of sed-fu. If it were a script, yep, avoid bashisms.
rq
One issue I've found with the code: What happens if the files were already renamed and I run it again? I get warnings for trying move into a subdirectory of itself.
Nerdling
To avoid re-run errors, you can use the same pattern in the "*.pkg" part, ie "for i in *-[0-9.]*.pkg ; do mv $i ${i/-[0-9.]*.pkg/.pkg} ; done". But the errors are innocuous enough (moving to the same file).
rq
+1  A: 

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.

Diego Sevilla
They are all in the same directory.What do you think of rq's answer?
Nerdling
I like not to use bash-specific features, but more standard sh instead.
Diego Sevilla
I assumed this was for a quicky rename, not for writing the next generation cross platform, portable Enterprise Application ;-)
rq
Haha, fair enough... Just out of a portability-minded man like me :)
Diego Sevilla
This one doesn't account for the third example: xorg-libXrandr (hyphen used in name).
Nerdling
Nerdling: I'm sorry to disagree, but of course it works for the third example. Please, try the code if you don't believe me.
Diego Sevilla
Ah, I see what the problem was. I ran yours after I ran rq's code. I'll try it again.
Nerdling
Alright, cool. Yours works as well (with same side effects as rq — he has a solution for that in his comments).
Nerdling
A: 

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 trainling | 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
Diomidis Spinellis