LinuxQuestions.org
Share your knowledge at the LQ Wiki.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 07-07-2006, 01:47 PM   #1
cjstm
LQ Newbie
 
Registered: Sep 2003
Location: Texas
Distribution: ubuntu
Posts: 18

Rep: Reputation: 0
bash script help


I am looking for a bash script that would help me rename a bunch of pics that I had on a Winblows machine. The files look like this

/granny/grannypics_(1001).jpg

I would like to rename them to something like this

/granny/grannypics.1001.jpg

I just recently switched from Winblows to ubuntu, not a noob but not a pro either, not scared to use the cli.

I have found a bash script that takes all the blank spaces out of file names I don't know if it can be modified to do what was explained above, but here it is if it helps

for i in `find . | tr "[:blank:]" "+" | grep "+"`; do echo "Changing Directory: " `echo $i | sed -r 's/\+/\\ /g'` " to " `echo $i | tr "+" "_"`; mv "`echo $i | sed -r 's/\+/\\ /g'`" `echo $i | tr "+" "_"`; done

If someone could explain to me how this script works or how to modify it to do the above I would be thankful. I could go in and edit each picture which would not be a big deal if there where one or two pics but I have over 10,000 to do so it would be a real pain one by one

Let me thank who ever responds to this thread in advance

Last edited by cjstm; 07-07-2006 at 01:49 PM.
 
Old 07-07-2006, 02:14 PM   #2
spirit receiver
Member
 
Registered: May 2006
Location: Frankfurt, Germany
Distribution: SUSE 10.2
Posts: 424

Rep: Reputation: 33
That script looks too complicated. Try this:
Code:
for FILE in /granny/grannypics_*.jpg; do mv -i $FILE $( echo -n $FILE | tr _ . | tr -d "()" ); done
Edit: Added the -i switch to mv. Note that I didn't test this, hopefully it won't do any harm.

Last edited by spirit receiver; 07-07-2006 at 02:18 PM.
 
Old 07-07-2006, 02:17 PM   #3
bit128_linux
Member
 
Registered: Dec 2005
Location: Brasov, Romania
Distribution: Slackware, Bluewhite64
Posts: 49

Rep: Reputation: 15
I think this should work:

for i in *.jpg; do FN=$(echo "$i" | sed 's/_(/./g' | sed 's/)//g') ; mv "$i" "$FN" ; done

Try with some 10-20 files in another dir to see if it works .
 
Old 07-07-2006, 02:19 PM   #4
cjstm
LQ Newbie
 
Registered: Sep 2003
Location: Texas
Distribution: ubuntu
Posts: 18

Original Poster
Rep: Reputation: 0
Thanks going to go try it
 
Old 07-07-2006, 02:20 PM   #5
MensaWater
LQ Guru
 
Registered: May 2005
Location: Atlanta Georgia USA
Distribution: Redhat (RHEL), CentOS, Fedora, CoreOS, Debian, FreeBSD, HP-UX, Solaris, SCO
Posts: 7,831
Blog Entries: 15

Rep: Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669
Try typing this at command line and you'll see it display (not actually rename) the new name you want:
Code:
echo "/granny/grannypics_(1001).jpg" |sed s/_\(/./ |sed s/\)//
You have to encapsulate the file name in quotes because the parentheses have special meaning to the shell and most commands. The echo just says "display this". What is being displayed is "piped" (the veritical bar) into the first sed command.

The first sed is doing a (s)ubstitute. The format of substitute is forward slash, search pattern, forward slash, replacement pattern, forward slash. Our search pattern is _( but since ( is a special charater it has to be "escaped" with the backslash so the pattern becomes _\( instead. The replacment is the dot. We then have to pipe (vertical bar again) into another sed to substitute the ) with nothing. Again it has to be escaped so pattern becomes \). Since we aren't actually replacing that with anything we just put in the final forward slash (make sure there is no space between it and the other forward slash.

The rest of it is to encapsulate it in a for loop to make sure it does this for multiple files rather than just the grannypics_(1001).

Code:
for OLDNAME in `ls *jpg`
do NEWNAME=`echo "${OLDNAME}" |sed s/_\(/./ |sed s/\)//`
   mv $OLDNAME $NEWNAME
done
This for loop sets OLDNAME as the variable name for each of the pictures presented by "ls *jpg" because we put backticks (not single quotes) around ls *jpg which means execute the command then use only its output (sort of a reverse pipe).

We then use the original command above but substitute the variable name for grannypics_(1001).jpg. We set this as a variable called NEWNAME. (Note the backtick usage again).

Finally we tell it to move the file from its old name to its new name.

The "for", "do" and "done" are required keywords of the loop. The "for" defines each item to do the loop on. The "do" specifies what to do to each item (this can be multiple lines long and can contain other loops and if/then conditionals). The "done" lets it know the "do" is complete.

Prior to actually running the above try doing:

Code:
for OLDNAME in `ls *jpg`
do NEWNAME=`echo "${OLDNAME}" |sed s/_\(/./ |sed s/\)//`
   echo oldname is $OLDNAME and newname is $NEWNAME
done
This will simply show you what it gets for each variable rather than actually moving anything. Once you are sure it has the correct variable values you want then you can run the original for loop above.

Your original script is doing translations and other things but is essentially the same thing. It uses i ($i) as the variable name. The variable name is abitrary. You just have to remember whatever you name it that you call it by that name (e.g. "for billybob in" would require you to use $billybob within the do/done.) Also note the special usage of variable ${billybob}. This is the same as $billybob but insures that if you have anything AFTER the variable name that you want to append that it doesn't think it is PART of the variable name.
 
Old 07-07-2006, 02:31 PM   #6
spirit receiver
Member
 
Registered: May 2006
Location: Frankfurt, Germany
Distribution: SUSE 10.2
Posts: 424

Rep: Reputation: 33
Here's another one:
Code:
mmv '/granny/grannypics_(*).jpg' '/granny/grannypics.#1.jpg'
Here you could use the -n and -v switches to see if everything works properly.
 
Old 07-07-2006, 02:41 PM   #7
cjstm
LQ Newbie
 
Registered: Sep 2003
Location: Texas
Distribution: ubuntu
Posts: 18

Original Poster
Rep: Reputation: 0
OOOOHHHHH you guys/girls are good. Worked like a charm. I am just starting to understand the power of the command Line.

Thanks again for your assistance it was a great help.

Thanks for the write up JLightner, it explained alot of what is going on. Boy do I have a lot to learn about the command line.

charlie

Last edited by cjstm; 07-07-2006 at 02:47 PM.
 
Old 07-08-2006, 08:43 PM   #8
jlinkels
LQ Guru
 
Registered: Oct 2003
Location: Bonaire, Leeuwarden
Distribution: Debian /Jessie/Stretch/Sid, Linux Mint DE
Posts: 5,195

Rep: Reputation: 1043Reputation: 1043Reputation: 1043Reputation: 1043Reputation: 1043Reputation: 1043Reputation: 1043Reputation: 1043
Charlie,

FYI, maybe not applicable in this special example, but there is the "rename" command in Linux. (It might or might not be installed with your distro)

Syntax is like:
Code:
rename s/oldpattern/newpattern/ filemask
thus for example if you want to change all underscores to dashes in you jpg files:
Code:
rename s/_/-/ *.jpg
The "s/oldpattern/newpattern/" is exactly the syntax as in the previous examples. (Guess what "rename" uses internally!)

In your case you would have had to run "rename" three times, but then you don't have to write a script.

The other methods work posted here work equally well I assume.

jlinkels
 
Old 07-08-2006, 09:28 PM   #9
jschiwal
LQ Guru
 
Registered: Aug 2001
Location: Fargo, ND
Distribution: SuSE AMD64
Posts: 15,733

Rep: Reputation: 682Reputation: 682Reputation: 682Reputation: 682Reputation: 682Reputation: 682
Here is another way:
for file in granny*; do
> mv -v "$file" "${file//[()]/}"
> done

Double quotes are used so that the () character don't start a subshell in bash. This example points out that you can use character classes in filename expansion.
 
Old 07-09-2006, 04:11 AM   #10
firstfire
Member
 
Registered: Mar 2006
Location: Ekaterinburg, Russia
Distribution: Debian, Ubuntu
Posts: 709

Rep: Reputation: 428Reputation: 428Reputation: 428Reputation: 428Reputation: 428
Hi, friends!
I have a little "amendment":
Quote:
Originally Posted by jlightner
Our search pattern is _( but since ( is a special charater it has to be "escaped" with the backslash so the pattern becomes _\( instead.
In `sed' characters `(' and `)' doesn't have a special meaning, but escaped ones '\(', '\)' -- does. On the contrary, in `Perl' parentheses -- is a grouping char's, and escaped ones -- not.

Cheers!
 
Old 07-10-2006, 08:22 AM   #11
MensaWater
LQ Guru
 
Registered: May 2005
Location: Atlanta Georgia USA
Distribution: Redhat (RHEL), CentOS, Fedora, CoreOS, Debian, FreeBSD, HP-UX, Solaris, SCO
Posts: 7,831
Blog Entries: 15

Rep: Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669
Quote:
Originally Posted by firstfire
Hi, friends!
I have a little "amendment":


In `sed' characters `(' and `)' doesn't have a special meaning, but escaped ones '\(', '\)' -- does. On the contrary, in `Perl' parentheses -- is a grouping char's, and escaped ones -- not.

Cheers!

Lets put it this way - without escaping the parentheses in the sed usage I listed it does NOT work. If you'd rather say they need to be escaped because of the shell rather than sed have at it.
 
Old 07-11-2006, 01:36 PM   #12
firstfire
Member
 
Registered: Mar 2006
Location: Ekaterinburg, Russia
Distribution: Debian, Ubuntu
Posts: 709

Rep: Reputation: 428Reputation: 428Reputation: 428Reputation: 428Reputation: 428
Quote:
Originally Posted by jlightner
Code:
echo "/granny/grannypics_(1001).jpg" |sed s/_\(/./ |sed s/\)//
Oh, sorry.
I use apostrophes and you -- not. My variant looks like this:
Code:
echo "/granny/grannypics_(1001).jpg" |sed 's/_(/./' |sed 's/)//'

Let me say sorry one more time! I'm distrait a little.
 
Old 07-12-2006, 03:19 PM   #13
MensaWater
LQ Guru
 
Registered: May 2005
Location: Atlanta Georgia USA
Distribution: Redhat (RHEL), CentOS, Fedora, CoreOS, Debian, FreeBSD, HP-UX, Solaris, SCO
Posts: 7,831
Blog Entries: 15

Rep: Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669
No worries. The great thing about UNIX/Linux is there's a thousand ways to do anything.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
building a bash script from an install script paranoid times Programming 6 07-29-2006 03:24 AM
Bash script - executing a script through subdirectories bubkus_jones Programming 5 04-24-2006 05:05 PM
send automatic input to a script called by another script in bash programming jorgecab Programming 2 04-01-2004 12:20 AM
bash script - incrementing a filename in a script tslinux Programming 10 08-05-2003 11:58 PM
bash script prob: how can i tell the script that a 'dd' has finished? Frustin Linux - General 2 04-02-2003 05:34 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 06:40 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration