[ale] Anyone want to crtique a shell script?
Scott Plante
splante at insightsys.com
Tue Apr 14 16:46:48 EDT 2015
I'll take a whack at it. Sorry for the delay, I wanted to wait until I had time to really have a good look.
One thing that's often overlooked in shell scripts is that you can redirect the output
of a block of statements at once. I often see stuff like
echo a > filename
echo b >> filename
echo c >> filename
instead of
{
echo a
echo b
echo c
} > filename
The latter also has the advantage of only opening the file once, instead of 3 (or x) times. It may not
seem more concise & readable here (2 extra lines!) but in practice it usually is. Or especially in cases
like yours where the block (for loop) is already there.
Also, for simple "if" conditionals where there isn't both a true and false statement,
and especially where there's only a single statement to execute conditionally, you can
use the handy && and || connectors. && means execute the next statement if the previous
returned 0 exit code (true/no error), and || when non-zero/false.
e.g. [ -f "$file" ] && true > "$file"
And for short sanity checks, I often do this kind of thing even though it's two statements:
[ -f "$reqfile" ] ||
{ echo "$reqfile is required" 1>&2; exit 1; }
or in your case:
[ -z "$RELEASE" ] &&
{ echo "Please provide a release number." 1>&2; exit 2; }
Somebody mentioned about the non-zero exit codes already. Also, the 1>&2 sends the
message to std err, which would be the convention.
An aside:
I often use the simple
> $file
and I've seen
: > $file"
Note ":" is the null statement. In my e.g. I used "true" as it's concise and emits no output
but is unlikely to be overlooked. If you think cat /dev/null is more readable then that's
fine, but I don't know if I'd say any are very much better than the others. I think the cat /dev/null
is mostly more readable if you're used to seeing it and not used to seeing the others, but there
are no absolute answers in stylistic questions.
I'm a bit unsure what's meant to be in default, but it seems like the "-r RELEASE" option is not meant
to be optional. If that's true, you shouldn't have it in square brackets in your help message. But maybe
you mean it's optional if it's in the default?
I'm not a big getopts user so I'm going to assume that's all working correctly. I have a vague memory that
it had some kind of notation for which options were required, but I could be confused.
There is a handy little dev file /dev/stdout you can use for standard out when you need a file placeholder.
I don't see exactly in your script where OUTFILE could be empty, so I just added a check before the "for file in":
So you could make the last block a lot more concise like this:
[ -z "${OUTFILE}" ] && OUTFILE=/dev/stdout
for file in install network services partitions packages pre post
do
if [ -f "${file}.${RELEASE}.${SUFFIX}" ]
cat "${file}.${RELEASE}.${SUFFIX}"
elif [ -f "${file}.${RELEASE}" ]
cat "${file}.${RELEASE}"
else
cat "${file}"
fi
done > "${OUTFILE}"
In Linux we don't often get files/directories with white space in them, but I always try to account
for the possibility. Hence the added double quotes around "$OUTFILE" etc.
Ok I lied--not always--typing all those quotes does get old. But usually at least if it's meant to be a
long-lived script and/or other people will use it. I have the same problem w/ the curly braces on
variables. At least with them, it's not dependent on the value of the variable--if it works without the
curlies, it'll always work.
One minor stylistic/convention point. I notice you sometimes use all caps variable names and sometimes
lower case. I was taught that environment variables were all-caps to differentiate them from the ones
in your scripts. So I believe OUTFILE, RELEASE, etc. should all be lowercase. The first shell variables
people learn about are environment variables so they seem to think all shell variable should be caps,
and this old convention is widely ignored or unknown, or maybe I was taught wrong :-P get off my lawn!
FWIW, I've written many shell scripts over the years and never known a missing line-end semicolon to
cause problems. Well at least if you actually end the line. You need them if you want to type
{ cmd-a; cmd-b; }
instead of
{
cmd-a
cmd-b
}
Not to say there isn't some edge case, but I'd be very curious to see it. Then again,
I sometimes add the superfluous semis out of habit from other languages.
Scott
p.s. One last thought occurred to me. After fixing whatever typos, you could try something like this:
for prefix in install network services partitions packages pre post
do
for file in "${prefix}.${RELEASE}.${SUFFIX}" "${prefix}.${RELEASE}" "${prefix}"
do
[ -f "$file" ] && { cat "${file}"; continue 2; }
done
done > "${OUTFILE}"
----- Original Message -----
From: "Leam Hall" <leamhall at gmail.com>
To: "Atlanta Linux Enthusiasts" <ale at ale.org>
Sent: Saturday, April 11, 2015 10:22:59 AM
Subject: [ale] Anyone want to crtique a shell script?
Could use critique on a shell script that writes Kickstart files. You
don't have to understand Kickstart to critique, the output files are
plain text in a certain order.
https://github.com/LeamHall/SecComFrame/tree/master/tools/ks_writer
The script is ks_writer.sh and the other files there are what gets
pulled in and what an output might look like.
Thanks!
Leam
_______________________________________________
Ale mailing list
Ale at ale.org
http://mail.ale.org/mailman/listinfo/ale
See JOBS, ANNOUNCE and SCHOOLS lists at
http://mail.ale.org/mailman/listinfo
More information about the Ale
mailing list