Basic Bash Scripting Question

Discuss Programming
User avatar
Calum
guru
guru
Posts: 1349
Joined: Fri Jan 10, 2003 11:32 am
Location: Bonny Scotland
Contact:

Basic Bash Scripting Question

Post by Calum » Tue May 13, 2003 1:52 pm

i'm not too great at scripting but anyway here's what i want to do.

I have come by a handful of windows media audio files, and i would like to convert them to mp3s. This is a two stage process, which i am doing as follows at a prompt:

Code: Select all

$ mplayer -ao pcm -aofile filename.wav filename.wmv
$ lame -h -b 192 filename.wav filename.mp3
however this is a process where i must manually type in two commands per file. I wanted to make a script which would do a batch of files (say all of them in the current directory for instance) but i don't even know how. I think my problem is that i don't know how to specify the filenames as a variable, ie how to get "trackone.wmv" to become "trackone.wav" and then "trackone.mp3" without erasing or being erased by "tracktwo.wav" or whatever at any point. I have a feeling it's very simple, but what is it that i must do?

Thanks of course in advance.

X11
guru
guru
Posts: 676
Joined: Sun Jan 19, 2003 11:09 pm
Location: Australia
Contact:

Post by X11 » Tue May 13, 2003 4:05 pm

Code: Select all

mplayer -ao pcm -aofile %1.wav %1.wmv
lame -h -b 192 %1.wav %1.mp3
Save it as <insert name here>
chmod +x <insert name here>
and copy it to /usr/local/bin or ~/bin

User avatar
Calum
guru
guru
Posts: 1349
Joined: Fri Jan 10, 2003 11:32 am
Location: Bonny Scotland
Contact:

Post by Calum » Wed May 14, 2003 4:32 am

so the %1 will act as the filename in each case, enabling the files to be processed as a batch?

is there some sort of documentation i can read up about this from? i found "man bash" a bit unhelpful and i did print out the enormous GNU bash reference guide from the FSF site (well the first couple of hundred pages of it) but most of it is irrelevant to the purpose of learning basic bash scripting.

X11
guru
guru
Posts: 676
Joined: Sun Jan 19, 2003 11:09 pm
Location: Australia
Contact:

Post by X11 » Wed May 14, 2003 5:29 am

Well I learned from VoidMain, and some small docs i found on the web a while ago.

(checks google)

my god i typed simple bash scripting and guess what, the FIRST 7 where titled, ADVANCED BASH SCRIPTING (except the second)...

http://www.siliconjunkie.net/bashtutorial/

that might help

User avatar
Void Main
Site Admin
Site Admin
Posts: 5716
Joined: Wed Jan 08, 2003 5:24 am
Location: Tuxville, USA
Contact:

Post by Void Main » Wed May 14, 2003 6:26 am

Uh, that should be $1 instead of %1. We're not in Kansas any more Toto.

User avatar
Calum
guru
guru
Posts: 1349
Joined: Fri Jan 10, 2003 11:32 am
Location: Bonny Scotland
Contact:

Post by Calum » Wed May 14, 2003 11:56 am

okay and "$1" will do what i ask, right? thank you both.

User avatar
Void Main
Site Admin
Site Admin
Posts: 5716
Joined: Wed Jan 08, 2003 5:24 am
Location: Tuxville, USA
Contact:

Post by Void Main » Wed May 14, 2003 12:12 pm

Are you saying it would be helpfull to provide documentation with the code? :)

The first parameter passed to your script is held in the "$1" variable (second parameter is $2, third $3, etc). So say you called your script "wmv2mp3" and the file you wanted to convert is "filename.wmv" you would type "wmv2mp3 filename" (without the wmv extension) which should provide you with a "filename.mp3". It's just tying the commands together from your first example and using a parameter for the file name. Your script might look like this:

Code: Select all

#!/bin/bash
if [ $# -ne 1 ]; then
  echo "Syntax: `basename $0` wmvFilenameWithoutExtension"
  exit
fi
mplayer -ao pcm -aofile $1.wav $1.wmv
lame -h -b 192 $1.wav $1.mp3
I added one error check into the code for you in the "if" statement. It checks the number of parameters passed to the script and if it isn't exactly 1 parameter then the script will exit with a Syntax message. To be a really good script you might do some other checking, to make sure "filename.wmv" actually exists before trying to run the commands for instance. Not necessary but makes your script a little smarter.

With a check to see if the *.wmv file exists:

Code: Select all

#!/bin/bash
if [ $# -ne 1 ]; then
  echo "Syntax: `basename $0` wmvFilenameWithoutExtension"
  exit
fi
if [ ! -f "$1.wmv" ]; then
  echo "File $1.wmv not found!"
  echo "Syntax: `basename $0` wmvFilenameWithoutExtension"
  exit
fi
mplayer -ao pcm -aofile $1.wav $1.wmv
lame -h -b 192 $1.wav $1.mp3
Of course if you do it like this:

Code: Select all

#!/bin/bash
if [ $# -ne 1 ]; then
  echo "Syntax: `basename $0` wmvFilename"
  exit
fi
if [ ! -f "$1" ]; then
  echo "File $1 not found!"
  echo "Syntax: `basename $0` wmvFilename"
  exit
fi
mplayer -ao pcm -aofile ${1%%.wmv}.wav $1
lame -h -b 192 ${1%%.wmv}.wav ${1%%.wmv}.mp3
then you *can* pass it the full wmv filename (with extension). What is the advantage of this? Well, it makes it easier to use in another script or in a "for" loop on *.wmv files for instance, and it would be a little more standard with other conversion utilities.

User avatar
Calum
guru
guru
Posts: 1349
Joined: Fri Jan 10, 2003 11:32 am
Location: Bonny Scotland
Contact:

Post by Calum » Thu May 15, 2003 1:26 am

void main thank you for taking the time to explain this to me, that is more than i expected to say the least and is very helpful to me.

X11
guru
guru
Posts: 676
Joined: Sun Jan 19, 2003 11:09 pm
Location: Australia
Contact:

Post by X11 » Thu May 15, 2003 1:59 am

Sorry, I have been exposed to Windows at school, me and 2 other "J00 LeeT scripT0Rz" where writing net send scripts and soforth, sorry.

Oh and voidmain, you desereve a beer for the hard work you go thru, who could i send money to buy you "virtual beer" (they buy the beer for you, i pay for it).

User avatar
Calum
guru
guru
Posts: 1349
Joined: Fri Jan 10, 2003 11:32 am
Location: Bonny Scotland
Contact:

Post by Calum » Thu May 15, 2003 5:24 am

on the other hand, void main, does this actually allow a whole directory of files to be done in one go?
i know, i know, but i do know nothing about scripting really, it's not logical to me yet.
could i just call this script 'wma2mp3' and then do "wma2mp3 *" and it would take care of all the files in the directory? or would i have to envoke it six times with six different filenames (assuming i have a half dozen files in the current directory). i know this is a really dumb question but i can't see how to distinguish this from the script.

User avatar
Void Main
Site Admin
Site Admin
Posts: 5716
Joined: Wed Jan 08, 2003 5:24 am
Location: Tuxville, USA
Contact:

Post by Void Main » Thu May 15, 2003 8:02 am

Calum wrote:on the other hand, void main, does this actually allow a whole directory of files to be done in one go?
No, the example script will not do that, you didn't ask for that. :)
i know, i know, but i do know nothing about scripting really, it's not logical to me yet.
could i just call this script 'wma2mp3' and then do "wma2mp3 *" and it would take care of all the files in the directory? or would i have to envoke it six times with six different filenames (assuming i have a half dozen files in the current directory). i know this is a really dumb question but i can't see how to distinguish this from the script.
Ooops, just realized I have used "wma" extensions rather than "wmv". I will change the examples. You could use the existing script to do this if you wrap it in a for loop on the command line like this:

$ for file in *.wma; do wma2mp3 $file; done

Or if you wanted to add that functionality right into the script you could:

wma2mp3:

Code: Select all

#!/bin/bash
if [ $# -lt 1 ]; then
  echo "Syntax: `basename $0` wmvFilename(s)"
  exit
fi
if [ ! -f "$1" ]; then
  echo "File $1 not found!"
  echo "Syntax: `basename $0` wmvFilename(s)"
  exit
fi
for file in $*
do
  mplayer -ao pcm -aofile ${file%%.wma}.wav $file
  lame -h -b 192 ${file%%.wma}.wav ${file%%.wma}.mp3
done
Notice I changed the first error check to make sure there are "at least" 1 parameter. I also changed the "wmv" to "wma" wherever it occurred. I also added a for loop to take each parameter passed and convert it to mp3 so you should now be able to do:

$ wma2mp3 *.wma

The above command will only work on files that do not contain spaces in their names and the extesions must all be lower case "wma".

How does the above script work? Let's say you have 3 wma files in your directory called "file1.wma", "file2.wma", and "file3.wma". At the bash command line when you type "wma2mp3 *.wma" it (bash) will automatically expand the wildcard before executing the script, so as far as the script is concerned here is how you executed it:

$ wma2mp3 file1.wma file2.wma file3.wma

Now in the script $# would resolve to the number of args which in this case is "3". $0 resolves to the full name of the script, in this case might be "/usr/bin/wma2mp3". The "basename" command strips off the directory components from that file name so you are left with "wma2mp3".

The "$*" would be replaced with "file1.wma file2.wma file3.wma" so your for loop would end up looking like "for file in file1.wma file2.wma file3.wma" and execute the commands within the loop for each of the parameters individually placing each param in the variable called "file".

The "${file%%.wma}.mp3" is a bash trick to change the ".wma" portion of the variable "file" to ".mp3" (if what is contained in the variable ends with ".wma"). That way when the "lame" command is executed for instance, it has the proper parameters.

I think that's pretty much it, do you understand everything?
Last edited by Void Main on Thu May 15, 2003 10:33 am, edited 1 time in total.

User avatar
Calum
guru
guru
Posts: 1349
Joined: Fri Jan 10, 2003 11:32 am
Location: Bonny Scotland
Contact:

Post by Calum » Thu May 15, 2003 9:57 am


No, the example script will not do that, you didn't ask for that. :)
hmm, well maybe i didn't word it very well then, but i did try to say that:
(me): I wanted to make a script which would do a batch of files (say all of them in the current directory for instance)
Ooops, just realized I have used "wma" extensions rather than "wmv". I will change the examples.
six and half a dozen, it's the actual script itself that's new and therefore a little out of my league
I think that's pretty much it, do you understand everything?
well i completely appreciate you once again taking the time to explain all this to me. i wouldn't have come up with this on my own that's for sure! a lot of the conventions used here are new to me, such as -lt and -ne for instance, and i hadn't heard of basename or $0 before i don't think and the double percent signs in ${file%%.wma}.wav are new to me too.

but yes i do largely understand it and once more thank you for taking the time to explain it to me fully and comprehensibly. your input to this thread would probably make a useful tutorial, either in bash or in getting you rcomputer to convert wma files to a more sensible one. the script could easily be modified for conversion to ogg and flac i assume and once i am comfortable with how it works, i will probably be doing just that.

User avatar
Void Main
Site Admin
Site Admin
Posts: 5716
Joined: Wed Jan 08, 2003 5:24 am
Location: Tuxville, USA
Contact:

Post by Void Main » Thu May 15, 2003 10:48 am

Calum wrote:hmm, well maybe i didn't word it very well then, but i did try to say that:
Sorry about that. I'm not very observant. :)
but yes i do largely understand it and once more thank you for taking the time to explain it to me fully and comprehensibly. your input to this thread would probably make a useful tutorial, either in bash or in getting you rcomputer to convert wma files to a more sensible one. the script could easily be modified for conversion to ogg and flac i assume and once i am comfortable with how it works, i will probably be doing just that.
There are already a lot of good bash/shell tutorials so writing another one would just be redundant. Most people pick up basic scripting very quickly. It really does become second nature with little effort. And it is a good leap into something like C programming as you can learn some basics like conditionals, looping, functions, etc. The n00b tutorials I like are the ones that follow a similar format as what we did in this thread. Start you off with a basic script from a real need, then slowly add more functionality and new concepts. Eventually (actually in no time at all) you will look at this and go "COOL!". But you may want to not look at the previous link until you've looked at one like this.

I've never really looked at that second one but it was listed here so I figure it must be pretty good.

User avatar
Calum
guru
guru
Posts: 1349
Joined: Fri Jan 10, 2003 11:32 am
Location: Bonny Scotland
Contact:

Post by Calum » Fri May 16, 2003 6:11 am

well, of course the script works perfectly, i added one line to remove the wav file since it takes up a lot of space.

Code: Select all

#!/bin/bash
#wma2mp3 by void main
if [ $# -lt 1 ]; then
	echo "Syntax: 'basename $0' wmaFilename(s)"
	exit
fi
if [ ! -f "$1" ]; then
	echo "File $1 not found!"
	echo "Syntax: 'basename $0' wmaFilename(s)"
	exit
fi
for file in $*
do
	mplayer -ao pcm -aofile ${file%%.wma}.wav $file
	lame -h -b 192 ${file%%.wma}.wav ${file%%.wma}.mp3
	rm $[file%%.wma}.wav
done
the only thing is that the script doesn't appear to work with filenames containing spaces...
so to nag further, what's the way (if there is an easy one) to make it work with filenames which contain spaces?

Tux
guru
guru
Posts: 689
Joined: Wed Jan 08, 2003 10:40 am

Post by Tux » Fri May 16, 2003 8:48 am

Replacing them with underscores is the usual way.

Post Reply