[Gllug] spaces and shell scripting
Peter Grandi
pg_gllug at gllug.for.sabi.co.UK
Thu Sep 1 14:45:04 UTC 2005
>>> On Thu, 01 Sep 2005 14:43:50 +0100, Jon Dye <jon at pecorous.co.uk>
>>> said:
jon> Hi, I'm trying to write a shell (bash) script [ ... ]
jon> My problem is spaces in filenames and how to deal with them
jon> when I have a list of file names in a variable.
The usual ''solution'' is to ignore the issue. :-( Indeed most
''professional'' shell script out there are simply awful; not
many understand even the basics of shell scripting, and your
script is not worse than the average.
jon> I got the script to work by running find multiple times and
jon> not using variables, e.g. [ ... script ... ]
Using a two pass approach one could have written instead (note
the differences with yours):
#!/bin/sh
ME="`basename \"$0\"`"
doNoElements() { echo "$ME: no elements found"; }
doSingleElement() { echo "$ME: single element '$1'"; }
doOneOfManyElements() { echo "$ME: one of many elements '$1'"; }
C="`find ${1+\"$@\"} -type f -print | wc -l`"
case "$C" in
'0') doNoElements;;
'1')
: '1 file, scan again to get the name of that file'
find ${1+"$@"} -type f -print | while read FILE
do doSingleElement "$FILE"
done;;
*)
: 'N files, scan again to get the list'
find ${1+"$@"} -type f -print | while read FILE
do doOneOfManyElements "$FILE"
done;;
esac
It may be more efficient to usr '-print0 | xargs -0 ...' if the
processing is done by a single command that can take multiple
file arguments.
So, the above still requires two passes; this can be avoided
with some effort: the idea is to keep a count of file names
seen, and to process not the current file name, but the previous
one, as this allows a 1-degree of lookahead, and to special case
the cases where the unknown-length stream of file names is 0
tokens or 1 token long:
#!/bin/sh
ME="`basename \"$0\"`"
doNoElements() { echo "$ME: no elements found"; }
doSingleElement() { echo "$ME: single element '$1'"; }
doOneOfManyElements() { echo "$ME: one of many elements '$1'"; }
N='0'; PREV=''
: 'We ensure the last element is a terminating empty string.'
{ find ${1+"$@"} -type f -print; echo ''; } | while read FILE
do
case "$FILE" in
?*)
: 'Non empty element, check if it is the 0th, the 1st, or
a subsequent one.'
case "$N" in
'0') : 'Do precisely nothing; this is the first element';;
*)
: 'If the count it not 0, this must be the second or
larger element of the stream, process the previous
one.'
doOneOfManyElements "$PREV";;
esac
PREV="$FILE"
N="`expr \"$N\" + 1`";;
'')
: 'Empty terminator: if "$N" is 0, no files were found;
if 1, one file was found and has to be done;
if > 1 then the last file of many has to be done.'
case "$N" in
'0') doNoElements;;
'1') doSingleElement "$PREV";;
*) doOneOfManyElements "$PREV";;
esac;;
esac
done
OK, that should be all. To check:
mkdir /tmp/{empty,single,many}
touch /tmp/single/a /tmp/many/{a,b,c}
and run either script with the obvious argument.
Note: the above are quick'n'dirty lightly tested stuff...
--
Gllug mailing list - Gllug at gllug.org.uk
http://lists.gllug.org.uk/mailman/listinfo/gllug
More information about the GLLUG
mailing list