Click to See Complete Forum and Search --> : parsing parameters in shell script


pickarooney
12-29-2004, 05:54 PM
I'm writing a little script to burn files to CD with two basic elements.

1) make an image, given a list of files and a name for the CD
2) burn the image

I have the two parts working when run independently from the CL, but I'm having trouble taking in and assigning the parameters.

mkisofs -J -R -V "CD name" -o imagename.iso file1 file2 ... filen
cdrecord -v -pad speed=8 dev=/dev/dvd:1,0,0 imagename.iso

I want to call the script with burn2cd "name of CD" file1.txt file2.jpg ... filen.png but don't know how to do it so that $1 is assigned to "CD name" from the mkisofs command above and everything after that is added to the list of files to add to the image.

I also need to add some validation to check that the passed files exist, but I think that should be easy enough with a for-loop once they're passed in.

bradfordgd
12-29-2004, 06:13 PM
Using your example of;

burn2cd "name of CD" file1.txt file2.jpg ... filen.png

"name of CD" would be $1, file1.txt would be $2, file2.jpg would be $3 and so on. You could enclose your filenames in double quotes and lump them all together as $2 using your example again;

burn2cd "name of CD" "file1.txt file2.jpg filen.png"

pickarooney
12-29-2004, 06:54 PM
It's definitely an idea, and should work. The only problem is that it obliges the user to put quotes around the list of files, which causes tab-completion not to work when entering the list.
I think there's a way of using $0 to do this...

Or maybe it's $#, that seems to return the number of parameters
I tried to write a test script that will loop for the number of input parameters
but I can't get the syntax write for the second last line. It's a bit of an odd-looking example, but I'm just trying to get it to echo the parameters from 2 to n, alongside their position in the input list.

title=$1
par=1
echo "name is $title"
while [ $par -lt $# ]
do
let par=par+1
echo "parameter number $par is ${$par}"
done

ernieg
12-29-2004, 11:03 PM
You can also take a look at the builtin "shift" command in shell scripting. This causes $1 to drop off the argument stack and thus $2 becomes $1. Using that combined with $# you could use a while loop to parse all arguments untill none are left. There is more on this in the info or man pages for bash and sh.

Just a thought.
Good luck with your script!

pickarooney
12-30-2004, 04:00 AM
Ah, now I remember reading about left-shifting parameters a while back. This is what I need, I'm pretty sure. Cheers :)
I reconsidered the design of the script in the meantime, and decided not to take the cd name as a parameter but to prompt for it at the beginning, for several reasons:

1) user doesn't have to remember to put the name in before the file list
2) user doesn't have to put the quotes around the name if it's got spaces in
3) user can leave the name of the CD blank if (s)he wishes

This allowed me to use a very simple:


#!/bin/bash
echo "Enter CD title:"
read title

filelist=$*
echo "going to burn: '$filelist'."
mkisofs -J -R -V "$title" -o imagename.iso $*


This will work with spaceless filenames, but once they have spaces in them it gets messed up, whether I use $filelist or $* as the last parameter to mkisofs.
So I need to treat each argument separately and add it to the list with quotes.

I'll post the whole script once it's finished - hopefully this evening.

psi42
12-30-2004, 04:37 AM
My script is crude, but it works. I use it all the time. No argument parsing really, but it should help you a bit in other areas:

http://www.files.himring.homelinux.org/scripts/torch

EDIT: It's a mess too. Sorry. Too many little changes. :)
Got to clean it up some day.

EDIT: This thing is messier than the xterm source code...

~psi42

pickarooney
12-30-2004, 09:38 AM
Originally posted by psi42
My script is crude, but it works. I use it all the time. No argument parsing really, but it should help you a bit in other areas:

http://www.files.himring.homelinux.org/scripts/torch

EDIT: It's a mess too. Sorry. Too many little changes. :)
Got to clean it up some day.

EDIT: This thing is messier than the xterm source code...

~psi42

the two main lines in the script are
mkisofs -U -R -J -V "$title" -C `cdrecord -tao -dev /dev/hdc -msinfo` -M /dev/hdc $directory | \
cdrecord -v -dev /dev/hdc -multi -

I don't see the bit where $title is attributed a value, unless it's passed from another script, and it seems to only work for all the files in a given directory, which isn't what I'm trying to do.

looking at it again, I think you assign a name to $volname but call $title instead when making the CD

The problem I'm currently left with is that the behaviour of mkisofs differs when given parameters via a script than when given them from the command line.
From the CL, you can say mkisofs -J -R -V "$title" -o imagename.iso "My file name.jpg"
and the filename in quotes gets converted to (I'm guessing) the name of the file with escaped characters, e.g. My\ File\ Name.jpg before mkisofs handles it.
If you pass the same parameter within a bash script, it's merely interpreted as is, and three separate things are passed to mkisofs, which can't understand them:
"My
File
Name.jpg"

Perhaps I can use sed to reconvert
"My File Name.jpg" or
My File Name.jpg to
My\ File\ Name.jpg before mkisofs handles it.

Thanks for the example/suggestion in any case :)

bwkaz
12-30-2004, 10:40 AM
cdname="$1"

shift

mkisofs -J -R -V "$cdname" -o imagename.iso "$@"
cdrecord -v -pad speed=8 dev=/dev/dvd:1,0,0 imagename.iso $1 and $cdname must ALWAYS be put into quotes, because they can easily have spaces in them.

You have to shift $1 out of the way after saving it, so that it doesn't get substituted in with "$@" ($@ is all the positional parameters, starting with 1).

You also need to use "$@", because your filenames may have spaces in them -- so $* is a really bad idea, because it doesn't preserve the actual argument separators (if you pass your script a filename called "file 1.blah", then $* will turn it into two arguments, "file" and "1.blah", while "$@" will leave it one argument).

pickarooney
12-30-2004, 11:13 AM
ah-ha, the @ should solve it so?
Sweet, looking forward to trying that later.

Try a google search for "$@" ;)

bwkaz
12-30-2004, 07:54 PM
Originally posted by pickarooney
Try a google search for "$@" ;) Heh -- a better way to see what it does is to do a bash manpage search for \@ (you need the backslash because otherwise the regex parser used by less thinks it's referring to a previous regex).

pickarooney
12-30-2004, 08:26 PM
well it seems to work like a charm:

#!/bin/bash
echo "Enter CD title:"
read title

mkisofs -J -R -V "$title" -o "$title".iso "$@"
cdrecord -v -pad speed=8 dev=/dev/dvd:1,0,0 "$title".iso


so easy when you know the symbols. :D


BTW, man \@ gives nada.

psi42
12-30-2004, 08:40 PM
Originally posted by pickarooney

I don't see the bit where $title is attributed a value, unless it's passed from another script, and it seems to only work for all the files in a given directory, which isn't what I'm trying to do.

looking at it again, I think you assign a name to $volname but call $title instead when making the CD


Yeah... like I said, it's a mess. I should have put $volname instead of $title...

The script will work for any files you pass to it:

torch file1 /path/to/file2.jpg /path/to/dir


I need to clean it up, though.


Thanks for the example/suggestion in any case :)

No problem. :)
~psi42

pickarooney
12-31-2004, 07:10 AM
Ah yes, now I see it ( cp -rv $@ $tempisodir; directory=$tempisodir).
I missed the reassignment of $directory once you'd copied all the files in there.

bwkaz
12-31-2004, 11:09 AM
Originally posted by pickarooney
BTW, man \@ gives nada. I know. You need to do man bash, then hit the slash key to search the page, and type in \@ and hit return. You have to search a couple of times to actually find the relevant comment, though -- subsequent searches for the same pattern may be done by hitting slash and return immediately.

(That's forward slash -- / -- not backslash.)

pickarooney
01-04-2005, 03:08 PM
I don't know if I should add this here or open a new thread, but I can't seem to burn readable CDs. Two out of three burned CDs are unreadable (the last track can't be read, the other tracks are OK) with this:

cdrecord -v -pad -tao speed=8 dev=/dev/dvd:1,0,0 /tmp/diskfile.iso

Are there any parameters I can pass to reduce the likelihood of CDs getting destroyed? The burner goes up to 52 speed, but I burn at 8 for safety's sake.
With k3b I usually lose one in about 5 CDs, but this is just too many.

Would the burnfree/overburn switches help?