LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Bash Renaming (removing a string from filenames) (https://www.linuxquestions.org/questions/programming-9/bash-renaming-removing-a-string-from-filenames-465649/)

FreeDoughnut 07-19-2006 03:56 PM

Bash Renaming (removing a string from filenames)
 
I switched CD ripping programs recently, and the first one didn't organize my music in folders. The new one does, so I did it manually. What I have now is:
Quote:

/mnt/music/music/Pink Floyd/Dark Side Of The Moon/Pink Floyd - Eclipse.ogg #OLD
/mnt/music/music/Rush/Moving Pictures/Tom Sawyer.ogg #NEW
So I'm working on a bash command to change the old ones to be like the new ones. What I have so far from my Googling is:
Quote:

for i in `ls`; do mv $i `echo $i | sed ' s/Pink\ Floyd\ -\ /\ /' `; done
But due to some discrepency between sed and mv and the for loop, mv processes each space seperated part as a seperate file, so I get errors like:
Quote:

mv: invalid option -- \
Try `mv -help' for more information.
mv: cannot stat `Us\\': No such file or directory
mv: cannot stat `And\\': No such file or directory
mv: cannot stat `Them.ogg': No such file or directory
However,
Quote:

mv "Pink Floyd - Money.ogg" `echo "Pink Floyd - Money.ogg" | sed ' s/Pink\ Floyd\ -\ //' `
gives me "Money.ogg". How do I coordinate every program's way of processing "\ "s and " "s so that I can make my music collection consistent?

Thanks for any help, and I'm a newbie to bash scripting, so please explain any changes to my original command.

FreeDoughnut 07-19-2006 04:05 PM

D'oh! I feel like hitting myself. I always figure my questions out right after posting.
I ended up replacing "for i in `ls`" with "for i in *"
So for any other Bash newbies out there, my final command is:
Quote:

for i in *; do mv "$i" "`echo "$i" | sed ' s/Pink\ Floyd\ -\ //' `"; done

taylor_venable 07-19-2006 05:06 PM

Actually, I think it was putting the double quotes around $i and your sed command (the parameters to the mv program) that fixed it...

And for safety's sake (because you have, I believe, incorrectly nested quotes) you might want to remove the double quotes around the $i parameter to the echo command. In other words, I would try:

Code:

for i in `ls -1`; do mv "$i" "`echo $i | sed ' s/Pink\ Floyd\ -\ //' `"; done
It may work now, which is good, but I think these fixes may make it more stable. :)

spooon 07-19-2006 05:43 PM

A much better way of renaming files is
Code:

rename "Pink Floyd - " "" *
Quote:

Originally Posted by taylor_venable
Actually, I think it was putting the double quotes around $i and your sed command (the parameters to the mv program) that fixed it...

And for safety's sake (because you have, I believe, incorrectly nested quotes) you might want to remove the double quotes around the $i parameter to the echo command. In other words, I would try:

Code:

for i in `ls -1`; do mv "$i" "`echo $i | sed ' s/Pink\ Floyd\ -\ //' `"; done
It may work now, which is good, but I think these fixes may make it more stable. :)

This won't work. Because the for loop takes a list, and the list separator characters include space, the for loop will iterate through each space-separated word, and this has nothing to do with the quoting of $i. So you would either have to temporarily change the list separator characters; or use the read command:
Code:

ls -1 | while read i; do mv "$i" "`echo $i | sed ' s/Pink\ Floyd\ -\ //' `"; done

FreeDoughnut 07-19-2006 07:35 PM

Well, thanks for all your input! I figured out how to do it, and now have an easier way for in the future. This forum is great.

taylor_venable 07-19-2006 10:01 PM

Quote:

Originally Posted by spooon
This won't work. Because the for loop takes a list, and the list separator characters include space, the for loop will iterate through each space-separated word, and this has nothing to do with the quoting of $i.

Oh, yeah; my mistake. So when you use the star * wildcard, it must automatically escape special characters when it's expanded, right? Otherwise it would cause the same problem. Is it therefore not necessary to quote $i in this case, because the spaces and such are already escaped? (I notice you still quote it in your example, so I'm wondering.) Thanks.

spooon 07-19-2006 10:13 PM

Quote:

Originally Posted by taylor_venable
Oh, yeah; my mistake. So when you use the star * wildcard, it must automatically escape special characters when it's expanded, right? Otherwise it would cause the same problem. Is it therefore not necessary to quote $i in this case, because the spaces and such are already escaped? (I notice you still quote it in your example, so I'm wondering.) Thanks.

In my example, I didn't use a for loop at all. I use read in a while loop to read one line at at time from the output of "ls -1".

spirit receiver 07-20-2006 01:38 AM

Quote:

Originally Posted by FreeDoughnut
But due to some discrepency between sed and mv and the for loop, mv processes each space seperated part as a seperate file,

That's because of the loop, the argument of the loop will be split at space characters (among others) into the separate parameters for each loop. You can change that behaviour by setting the IFS internal variable in Bash, for example IFS=$'\n' makes sure that it will only be split at newline characters.

taylor_venable 07-20-2006 10:18 AM

Quote:

Originally Posted by taylor_venable
So when you use the star * wildcard, it must automatically escape special characters when it's expanded, right? Otherwise it would cause the same problem. Is it therefore not necessary to quote $i in this case, because the spaces and such are already escaped?

I'll answer my own question, in case anybody is interested. No, it is necessary to quote $i even when $i is generated as an expansion of the star wildcard. Failing to quote $i in this situation will cause an error for the mv program because of the spaces embedded in the filename. And this is why putting spaces in filenames is evil. :)

konsolebox 07-20-2006 09:54 PM

to FreeDoughnut:

you may also use $(...) instead of `...`. it's more stable and can be nested. remember that this is not available in sh.

on your command by the way. you might also use:

Code:

for a in *; do echo mv "$a" "${a/* - }"; done
remove the echo if you think the code is already correct
no need to use sed there

read the parameter expansion section of bash's manual. do man bash. it can really help.


All times are GMT -5. The time now is 10:46 AM.