Need a little help with my first shell script. Basic image resize script...


 
Thread Tools Search this Thread
Top Forums Shell Programming and Scripting Need a little help with my first shell script. Basic image resize script...
# 1  
Old 10-03-2015
Display Need a little help with my first shell script. Basic image resize script...

Hey everyone, just now joined because I didn't want to go onto Ubuntu forums and start asking about how to write shell scripts. Seems like this is a pretty active forum for exactly what I need.

I'm trying to modify a shell script I found online, the end goal is to have it find all files in the directory it's ran AND all subdirectories, named folder.jpg, Folder.jpg, maybe a couple more, and make thumbnails of them.

I found this script earlier, which initially was trying to resize ALL files.. mp3 and what not (because of the FILES=* I'm guessing):

Code:
#!/bin/bash
FILES=*
for f in $FILES
do
echo “Processing $f file...”

convert -thumbnail 235x $f sm_$f

done

So, I looked at this and figured I could probably replace the FILES=* with FILES=folder.jpg. Sure enough, it worked. But when I then assumed that FILES=folder.jpg Folder.jpg would work for both, I was sadly disappointed. No luck with a comma and space, comma no space, semicolon, etc. I believe with a semicolon after the first file, the script at least ran again.... lol

I've been trying to look it up but having no luck, there has to be some easy way to specify multiple file names in that situation.

As far as making it work on all subdirectories as well, I couldn't find much on that, but I did manage to read that I could do this....

Code:
find /your/dir/with/subdirs -type d -exec sh -c 'cd "{}" ; /path/to/your/script.sh ;' \;

Sure enough, it found the file I put in my test directory named folder.jpg, as well as the one in a nested directory! Would be nice to have it all packaged in a script just for the sake of not having to copy and paste that every time, but that works for now...

Also I just read about the option of making a "loop wrapper", like this...

Code:
#! /bin/bash
cd /path/to/top/level/directory

for d in */ ; do 
  pushd $d
  # call your script here
  popd
done

And plan on trying that here in a little. SO, it sounds like I'm good to go on the subdirectories part. But what about the multiple file names? Is there a way I can just put it in to the script easily, or I imagine somehow I could parse it into that find command I was using.

Also, with the original script it creates the thumbnails with the name "sm_*original-filename*.... If possible I'd like to change that to have them be named something like folder_small.jpg, or even something completely different like album_art_thumb.jpg.

When I tried changing "convert -thumbnail 235x $f sm_$f" to "convert -thumbnail 235x $f $f_small", it was a no-go. Didn't want to run at all. I imagine there's an easy way to fix that but this language is all new to me. I don't know anything besides some HTML, CSS, and how to get around on a Unix/Linux shell (been using nothing but Linux as my OS for about 8 years or so now... off and on before that since I was a little kid).

If you could please take the time and point me in the right direction, I'd really appreciate it! Again just trying to:

1. Specify multiple filenames to target, in the FILES= or otherwise...
and 2. How to change the end filename from sm_* to something that isn't text followed by the old filename.

And if you've got the time, maybe even help with the part about making it work recursively on all sub-directories.

Thanks! Glad to have found this forum. I can see how learning to make these scripts could really make a lot of things easier in the future... Smilie

Zac
# 2  
Old 10-03-2015
Perhaps, something like this

Code:
find . -type f -name "*.jpeg" | while read f
do
    echo "Processing ${f}…"
    convert -thumbnail 235x "$f" sm_"$f"
done

Based on your snippets; not tested.
# 3  
Old 10-03-2015
Hmm.. well that one didn't do anything for some reason. Not sure if it's because of me changing it to folder.jpg instead of the *.jpeg you had... I have one directory with a very large library of music and subdirectories, with additional album art that doesn't need to be converted. So just looking to do folder.jpg and maybe a couple more at the same time if possible. If not, I can always change the script and run for the other files.

I did manage to get a script running that will work recursively for one file. However, it only works when it's set up to name the new file something like "$f-thumb.jpg"... meaning it comes out like folder.jpg-thumb.jpg. When I just replaced the whole $f part with cover_small.jpg or something, it only worked on the main directory, and not subs.

Any ideas how I could fix that? Other than that, looks like I am getting there! This is actually quite a bit of fun.
# 4  
Old 10-03-2015
Yes, changing the -name "*.jpeg" to -name "folder.jpg" will only find files named as such and if it does not find any, well, it does nothing.

Here's an explanation of the find command
Code:
find . -type f -name "*.jpeg" # look for only files (no directories) and the file has to be be "anything.jpeg" recursively in each directory, starting at current directory

Would changing to just -name "*.jpg" work?

Last edited by Aia; 10-03-2015 at 04:07 PM..
# 5  
Old 10-03-2015
Sorry... I was trying to be as clear as possible. Maybe this is just a strange request, and that's why I can't find a script for it already.

I am not looking to convert all my .jpg files, only the ones named folder.jpg (the standard I decided on, for album cover art that I want to appear). If possible it'd be great to have it work for Folder.jpg and .jpeg of each too, since I'm sure I missed some.... but if I need to I can just edit the script and run a few times.

I was able to finally get it to work in the main dir and one below it, but I don't think it will go any further than that. The way that my filesystem is set up, I'm really going to need it to, or this will still take a good deal of manual labor.

Here is the script I am running now...

Code:
#!/bin/bash
for f in `find . -name "folder.jpg"`
do
    convert $f -resize 200x200\!  $f-thumb.jpg
done

The way it's set up now, the thumbnail files end up with names like folder.jpg-thumb.jpg. Is there any way I can change that to either adding something before the filename (i.e. small_folder.jpg) or an entirely new filename (i.e album_art_small.jpg)?

Tried just putting the filename I want instead of the $f-.jpg, and then it would only work in the main directory for some reason.

And again... pretty sure this script as I have it now will only work one subdirectory down. That's something I'll need to fix one way or another.

Thanks for your help! It is much appreciated.

Zac
# 6  
Old 10-03-2015
From your last example, try substitution:
Code:
convert $f -resize 200x200\!  ${f/\.jpg}-thumb.jpg

hth
# 7  
Old 10-03-2015
Quote:
Originally Posted by mozzles
I found this script earlier, which initially was trying to resize ALL files.. mp3 and what not (because of the FILES=* I'm guessing):

Code:
#!/bin/bash
FILES=*
for f in $FILES
do
echo “Processing $f file...”

convert -thumbnail 235x $f sm_$f

done

I suppose you are generally interested in learning to write shell scripts and not only to make the script going you are attempting to write. Therefore a little explanation why this (any other constructs similar to this) is a VERY BAD IDEA and you should never do it:

The "*" is interpreted by the shell first and replaced with its result: a list of all entries in the current directory. It is never a good idea to work with relative pathes inside a script. Execute a scriptin another path and this might mix up everything and render your system unusable.

Aside from this: say the directory contains 3 entries, "fileA", "fileB" and "fileC", then the line would be equivalent to:

Code:
FILES=fileA fileB fileC

The first problem is: not all entries in a directory have to be files. There are directories, links, FIFOs and more. Chances are your "convert" utility does not know how to handle them at all because it is built to work with a certain type of files and nothing else.

Another problem is: suppose you have lots of such files. A UNIX directory can easily handle millions of files (i have a few such systems). Imagine what your for-loop will do when it is presented this line:

Code:
for f in fileA fileB fileC ...many millions more... lastfile

The shell will simply give up and issue an "too many arguments"-error.

This is why such for-loops are never correct and always to be avoided. If you want to cycle through a list of files do it this way:

Code:
ls /path/to/dir | while read FILE ; do
     echo working on $FILE
done

If you want to modify your list you can either use shell-globs (*,?, ...) or text-filters to alter the list. For example, filter out every file with a number in the filename:

Code:
ls /path/to/dir | grep -v "[0-9]" | while read FILE ; do
     echo working on $FILE
done

Now, back to your problem, for which the find-command is the correct wa to do it.

Quote:
Originally Posted by mozzles
As far as making it work on all subdirectories as well, I couldn't find much on that, but I did manage to read that I could do this....

Code:
find /your/dir/with/subdirs -type d -exec sh -c 'cd "{}" ; /path/to/your/script.sh ;' \;

I have written a little introduction about how find works.

Quote:
Originally Posted by mozzles
When I tried changing "convert -thumbnail 235x $f sm_$f" to "convert -thumbnail 235x $f $f_small", it was a no-go.
Yes, because $f_small would be the content of a (non-existent) variable named "f_small". You can do whyt you want to do, but you need "variable expansion" for this, which is a bit complicated and probably not the first thing you want to learn.

For the sake of completeness, here you are:

Code:
f="example.jpg"

f_name="${f%.*}"
f_ext="${f##*.}"

echo "filename: $f_name   extension: $f_ext"

echo convert -thumbnail 235x "$f" "$f_name"_thumb."${f_ext}"


Quote:
Originally Posted by mozzles
1. Specify multiple filenames to target, in the FILES= or otherwise...
There are two ways to achieve this: put in multiple "-name"-clauses into the find-statement:

Code:
find /your/start/dir -type f \( -name "folder.jpg" -o -name "FOLDER.JPG" -o -name ....\) -exec ....

A second way is, when the names are related enough, to construct a single name-clause with a wildcard:

Code:
find /your/start/dir -type f -name "[Ff]older.jpg" -exec ....

Would find all files named "Folder.jpg" or "folder.jpg", for instance.

I hope this helps.

bakunin
Login or Register to Ask a Question

Previous Thread | Next Thread

10 More Discussions You Might Find Interesting

1. UNIX for Beginners Questions & Answers

Beginner bash - basic shell script 'while' help...

Hi everyone, first time visitor to these forums here. Keeping a long story short I've been attempting to learn how to code in bash. I have VERY little previous experience with coding languages besides simply copying and pasting batch scripts for Windows. So, with that in mind I've followed a... (4 Replies)
Discussion started by: Meta
4 Replies

2. Shell Programming and Scripting

Basic Shell script - Not working

Hello, This is basic (i think). I am trying to run a shell script which would go into each folder (folder names defined in the list) and after entering would run some commands, once done, come out of the folder and continue until the list ends. Pretty basic and there are bunch of example online. ... (9 Replies)
Discussion started by: Zam_1234
9 Replies

3. Shell Programming and Scripting

Basic Combination Shell Script

I need to have a script read a file that has a list of words in a single column like below:Black Blue Brown Orange Red Yellow Green White Purple Silver Grey Tan Then print to another file just all of the two-word possible combinations. Example: Black,Blue Anyone want to take a... (4 Replies)
Discussion started by: vespasian
4 Replies

4. Shell Programming and Scripting

Basic question on shell script execution

I have two shell scripts in the different directories listed below, /root/dev/dir1/test.sh /root/dev/dir2/master.sh I am executing the master.sh script from the test.sh like below and getting 'Permission denied' error. #! /bin/sh #test.sh path='/root/dev' $path/dir2/master.sh But it... (2 Replies)
Discussion started by: vel4ever
2 Replies

5. Shell Programming and Scripting

Help! Basic shell script advice

##### (2 Replies)
Discussion started by: AidoPotato
2 Replies

6. Shell Programming and Scripting

Basic shell script help

Im trying to make a script that simply adds a word to the last available line in a txt file without overwriting any previous lines. Ive googled this and there are great examples but no one explain what each function does, and i dont entirely understand how it works. Basically Im looking for... (7 Replies)
Discussion started by: kylecn
7 Replies

7. Shell Programming and Scripting

Basic Shell Script Help

Lets say I wanted to create a script that would show what people are doing on my machine using the w command and refresh in about 6 seconds. What would be the easiest way to do this? I pretty much want the script to loop until I stop it. I'm using the BASH shell by the way. Help is appreciated.... (1 Reply)
Discussion started by: c4391
1 Replies

8. Shell Programming and Scripting

shell script basic doubt

hi, I am new script learner, so my basic doubt is , how to store value of any command in a variable example $ ls | wc -l i want to stote the output of this in a variable c. so that i can use c in if else loop. and when do we use " ` " symbol in script.. can anyone also tell for... (5 Replies)
Discussion started by: hi2_t
5 Replies

9. Shell Programming and Scripting

Basic Shell script syntax help

Hi All, I am new to shell scripting. I have a variable which holds a numeric value.I have to check whether this variable holds a value between(0- 8),(8-17)(17-24).How do i write this syntax using if in shell scripting. Thanks Vignesh (2 Replies)
Discussion started by: vignesh53
2 Replies

10. Shell Programming and Scripting

need a quick basic shell script help

im trying to run the below if command ifconfig -a |grep 10.100.120.21 gives me below output inet addr:10.100.120.21 Bcast:10.100.120.255 Mask:255.255.255.0 i just want a basic shell which says if above exists then continue how would i do this? (6 Replies)
Discussion started by: eb222
6 Replies
Login or Register to Ask a Question