LinuxQuestions.org
Help answer threads with 0 replies.
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Newbie
User Name
Password
Linux - Newbie This Linux forum is for members that are new to Linux.
Just starting out and have a question? If it is not in the man pages or the how-to's this is the place!

Notices

Reply
 
LinkBack Search this Thread
Old 05-12-2013, 08:59 AM   #1
sam.pedraglio
Member
 
Registered: Jul 2005
Distribution: Mint 14 64bit
Posts: 67

Rep: Reputation: 16
Rename photo files


Hallo to everybody, I searched a lot in the net but I wasn't able to paste correctly the information I found.
I have a dir with a lot of jpg files; many of them have quite similar subjects (2 teacher visiting a museum with their students); I'd like to create a movie (I'll use Kdenlive) but I need to order them properly before.
I thought to use imagemagik tools:
Code:
identify -format %[EXIF:datetimeoriginal] a.jpg
I've created a file, called lista, containing all the files name.
If I try
Code:
for i in `cat lista`; do indentify -format %[EXIF:dateTimeOriginal] $i; done
my terminal gives me the correct list with all the date and time of creation.

I'd like to join this info to with the original filename.
I tried
Code:
origdir="../Foto Museo 16-04-13/"
destdir="./"
for i in `cat lista`; do cp "$origdir$i" "$destdir`identify -format %[EXIF:dateTimeOriginal] $i`$i"; done
but I obtained a simple copy of all the files from $origdir to $destdir with the original name.

I've tried a bash script too
Code:
#!/bin/bash
origdir="../Foto\ museo\ 16-04-13"
destdir="./"
for i in `cat lista` do
	datascatto=`identify -format %[EXIF:dateTimeOriginal] $origdir$i`
	echo cp "$origdir$i" "$destdir$datascatto$i"
done
but I obtained the following error message

Code:
./rinom: row 5: sintax error close to unattended token "datascatto=`identify -format %[EXIF:dateTimeOriginal] $origdir$i`"
./rinom: row 5: `	datascatto=`identify -format %[EXIF:dateTimeOriginal] $origdir$i`'
I tried to translate the Italian error but I'm not sure if I used the correct terms.

Could you help me to solve this problem?
Thanks in advance.
 
Old 05-12-2013, 09:23 AM   #2
goumba
Member
 
Registered: Dec 2009
Location: New Jersey, USA
Distribution: Debian Wheezy (7.0), Jessie (future 8) and Sid (unstable)
Posts: 469
Blog Entries: 2

Rep: Reputation: 52
The do in your for loop must either be preceeded by a semicolon (;) or on on a separate line.
 
Old 05-12-2013, 09:29 AM   #3
jdkaye
Senior Member
 
Registered: Dec 2008
Location: Westgate-on-Sea, Kent, UK
Distribution: Debian Testing Amd64
Posts: 4,028

Rep: Reputation: Disabled
Quote:
I tried to translate the Italian error but I'm not sure if I used the correct terms.
Are you talking about the Italian word "inatteso"? If that was the Italian original then "unexpected" is a better translation. "Unattented" means rather "incustodito" when speaking of luggage.
Ciao,
jdk
 
Old 05-12-2013, 04:28 PM   #4
sam.pedraglio
Member
 
Registered: Jul 2005
Distribution: Mint 14 64bit
Posts: 67

Original Poster
Rep: Reputation: 16
Quote:
Originally Posted by goumba View Post
The do in your for loop must either be preceeded by a semicolon (;) or on on a separate line.
I've correct the error; thanks for the input

Quote:
Are you talking about the Italian word "inatteso"? If that was the Italian original then "unexpected" is a better translation. "Unattented" means rather "incustodito" when speaking of luggage.
Ciao,
jdk
You're right. Wrong translation.


Unfortunately the script is not yet doing the right renaming: I continue to find non renamed files.
 
Old 05-12-2013, 06:18 PM   #5
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Debian sid + kde 3.5 & 4.4
Posts: 6,823

Rep: Reputation: 1946Reputation: 1946Reputation: 1946Reputation: 1946Reputation: 1946Reputation: 1946Reputation: 1946Reputation: 1946Reputation: 1946Reputation: 1946Reputation: 1946
Don't use a for loop on the contents of a file or command input! Always use a while+read loop. Especially when dealing with filenames.

How can I read a file (data stream, variable) line-by-line (and/or field-by-field)?
http://mywiki.wooledge.org/BashFAQ/001


Also, $(..) is highly recommended over `..`. Backticks are ugly, more prone to error, and pretty much deprecated.


Use either backslashes or quotes. Not both. I recommend quotes:
Code:
#origdir="../Foto\ museo\ 16-04-13"
origdir="../Foto museo 16-04-13"
Instead of reading from a file, I'd just loop over the files and grab the data directly. You can use a for loop for that.

Code:
#!/bin/bash
origdir="../Foto museo 16-04-13"
destdir="./"

for fname in "$origdir/"*; do

	datascatto=$( identify -format '%[EXIF:dateTimeOriginal]' "$fname" )
	echo cp -t "destdir" "$datascatto${fname##*/}"

done

I also seem to remember that imagemagick has some rather advanced file naming features built in, BTW. You might check the online site documentation.
 
Old 05-13-2013, 03:00 AM   #6
sam.pedraglio
Member
 
Registered: Jul 2005
Distribution: Mint 14 64bit
Posts: 67

Original Poster
Rep: Reputation: 16
Quote:
Originally Posted by David the H. View Post
Don't use a for loop on the contents of a file or command input! Always use a while+read loop. Especially when dealing with filenames.

How can I read a file (data stream, variable) line-by-line (and/or field-by-field)?
http://mywiki.wooledge.org/BashFAQ/001


Also, $(..) is highly recommended over `..`. Backticks are ugly, more prone to error, and pretty much deprecated.
I'll search for this opion, I started with for loop because I know its structure. :-)

Quote:
Use either backslashes or quotes. Not both. I recommend quotes:
Code:
#origdir="../Foto\ museo\ 16-04-13"
origdir="../Foto museo 16-04-13"
You're right, I'm sorry, I've corrected it in the Code section I used directly from the CLI but not in the script; in anycase I've used only the quotes.

Quote:
Instead of reading from a file, I'd just loop over the files and grab the data directly. You can use a for loop for that.

Code:
#!/bin/bash
origdir="../Foto museo 16-04-13"
destdir="./"

for fname in "$origdir/"*; do

	datascatto=$( identify -format '%[EXIF:dateTimeOriginal]' "$fname" )
	echo cp -t "destdir" "$datascatto${fname##*/}"

done
I used the file to work on selected files only.

Quote:
I also seem to remember that imagemagick has some rather advanced file naming features built in, BTW. You might check the online site documentation.
I red the documentation but I didn't find what i need, sorry, I'll try to read more carefully again.
 
Old 05-13-2013, 05:29 AM   #7
goumba
Member
 
Registered: Dec 2009
Location: New Jersey, USA
Distribution: Debian Wheezy (7.0), Jessie (future 8) and Sid (unstable)
Posts: 469
Blog Entries: 2

Rep: Reputation: 52
Quote:
Originally Posted by David the H. View Post
How can I read a file (data stream, variable) line-by-line (and/or field-by-field)?
http://mywiki.wooledge.org/BashFAQ/001
Thanks Dabid I had been trying to find that page while composing my reply but couldn't as it was not in my bookmarks. Done now.
 
Old 05-13-2013, 05:01 PM   #8
sam.pedraglio
Member
 
Registered: Jul 2005
Distribution: Mint 14 64bit
Posts: 67

Original Poster
Rep: Reputation: 16
Dear Sirs, first of all thanks for all your replies.
David, I've not yet iplemented the While loop, I've no time to read carefully the documentation but I'll do asap.

In any case I changed a bit my script, and now it does what I want.
Here the new release.
Code:
#!/bin/bash
for i in `cat lista`; do
        datascatto=`identify -format %[EXIF:dateTimeOriginal] $i|awk '{print $2}'|sed -e 's/:/-/g'`
        cp $i "$datascatto"_$i
done
Now I start from a file called
IMG_4381.jpg
and I arrive at the end with another file called
10-43-58_IMG_4381.jpg
Because the photo was taken on 16th of April at 10:43:58a.m.
 
Old 05-14-2013, 06:31 AM   #9
goumba
Member
 
Registered: Dec 2009
Location: New Jersey, USA
Distribution: Debian Wheezy (7.0), Jessie (future 8) and Sid (unstable)
Posts: 469
Blog Entries: 2

Rep: Reputation: 52
Code:
LISTFILE=lista

while read -r line
do
    EXIFINFO=$(identify -format %[EXIF:dateTimeOriginal] ${line} | sed -e 's/[ :]*/-/g')
    NEWFILE=$(dirname ${line})/${EXIFINFO}_$(basename ${line})
    cp ${line} ${NEWFILE}
done < $LISTFILE
Why did I use basename? If your list happens to have a path name included with the filename (such as "Photos/April16/IMG_4381.jpg"), the resulting name as you had it will be a bad filename ("10-43-58_Photos/April16/IMG_4381.jpg"). I use dirname and basename to fix that (now you'll get "Photos/April16/10-43-58_IMG_4381.jpg"). You can remove the dirname part if you want it copied to the current directory (the directory the script is being run in) along with the rest:

Code:
NEWFILE=${EXIFINFO}_$(basename ${line})
Also, the braces around the variable names prevents bash from including characters you do not want interpreted as part of the variable name from doing so. This is preferred to your quotes around "$datascatto" in the cp command above.

There's some basic error checking you can do as well, such as rejecting files with invalid EXIF data (such as none, or malformed file names).

Last edited by goumba; 05-14-2013 at 06:46 AM.
 
1 members found this post helpful.
Old 05-14-2013, 03:09 PM   #10
sam.pedraglio
Member
 
Registered: Jul 2005
Distribution: Mint 14 64bit
Posts: 67

Original Poster
Rep: Reputation: 16
Hi goumba, thanks so much for the script. I'll study it asap.
 
Old 05-15-2013, 02:05 PM   #11
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Debian sid + kde 3.5 & 4.4
Posts: 6,823

Rep: Reputation: 1946Reputation: 1946Reputation: 1946Reputation: 1946Reputation: 1946Reputation: 1946Reputation: 1946Reputation: 1946Reputation: 1946Reputation: 1946Reputation: 1946
If you want to operate on only certain files, it depends on what criteria you need to select them by.

If it's a simple name pattern and you don't need to work recursively, you can usually use a globbing pattern to select them. Bash also has an extra extended globbing system for added selective power.

(From version 4 there's also a new "**" globstar pattern that can be used to do recursive matching. Unfortunately it will currently lock up your shell session if it there are any recursive directory symlinks, so use it with caution.)

For more advanced matching, you probably need to use find, in which case you have to use a while loop with null delimiters (or often you can use its built-in -exec option instead of a shell loop).

You should also use the while loop if you have a file. Again, never use cat like that.

Once a string is in a variable, built-in shell string manipulations is usually better to use instead of external substitution commands (this includes basename, the pattern for which I demonstrated in my last post).

(Even when you do use external commands, a single sed or awk command can cover any number of lower-powered tools. You should almost never need chains of commands like "grep | sed | awk". Learn how to use your tools!)

Brackets around variables are only needed with parameter substitution, and if you have to separate the variable name from other characters that could be mistaken for it. Variable names can include letters, numbers, and the underscore. Otherwise they just clutter up the code and make it easier for errors to slip in. If you don't need it, leave it out.

And to repeat again, don't use backticks for command substitution. "$(..)" is the recommended pattern now.

Finally, QUOTE ALL OF YOUR VARIABLE EXPANSIONS. You should never leave the quotes off a parameter expansion unless you explicitly want the resulting string to be word-split by the shell and any possible globbing patterns expanded. This is a vitally important concept in scripting, so train yourself to do it correctly now. You can learn about the exceptions when you need them.

http://mywiki.wooledge.org/Arguments
http://mywiki.wooledge.org/WordSplitting
http://mywiki.wooledge.org/Quotes

goumba's version above is pretty much what you should be using, except for the unecessary basename and lack of safe quoting.

Code:
#!/bin/bash

listfile=lista
destdir='./'

while read -r fname; do

    etime=$( identify -format '%[EXIF:dateTimeOriginal]' "$line" )

    etime=${etime#* }             #remove everything up to the first space
    etime=${etime//:/-}           #replace colons with hyphens in the part that remains
    newname=${etime}_${fname##*/} #remove the path from the original filename
                                  # while building the final output file

    cp "$fname" "$destdir/$newname"

done < "$listfile"

If you want to process, for example, all .jpg files in the original directory, then glob it like this instead:

Code:
#!/bin/bash

origdir="../Foto museo 16-04-13"
destdir="./"

for fname in "$origdir/"*.jpg; do

   ...< as above > ...

done

Last edited by David the H.; 05-15-2013 at 02:12 PM. Reason: small corrections
 
1 members found this post helpful.
Old 05-16-2013, 08:11 AM   #12
goumba
Member
 
Registered: Dec 2009
Location: New Jersey, USA
Distribution: Debian Wheezy (7.0), Jessie (future 8) and Sid (unstable)
Posts: 469
Blog Entries: 2

Rep: Reputation: 52
Thank you, David the H, always learning learning something new here.

Certainly not as proficient in shell programming as others - I do little - but glad I got something right.
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

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
Trackbacks are Off
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Application to eliminate doubles in files and rename changed files with date? S. Chapelin Linux - Software 6 01-16-2011 02:02 AM
Copying photo files to CD -cyrus- Linux - Newbie 3 01-16-2010 11:11 PM
Trouble with making a bash script to read in different files and rename output files. rystke Linux - Software 1 05-07-2009 08:00 AM
get files from ftp and rename those files.. amaulana Linux - Newbie 2 11-15-2008 10:14 PM
Photo Suite .pzp files mickza Linux - Software 1 12-25-2006 10:46 AM


All times are GMT -5. The time now is 07:00 PM.

Main Menu
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
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration