[ILUG] bash script Q

Brian Foster blf at utvinternet.ie
Fri Apr 5 23:10:00 IST 2002


 1) Date: Fri, 5 Apr 2002 20:33:28 +0100
 1) From: John Tobin <tobinjt at netsoc.tcd.ie>
 1) 
 1) This seems to work for me and it's written entirely in bash:
 1) 
 1) #!/bin/bash
 1) for file in *; do if [ -f $file ]; then
 1) 	read LINE < $file;
 1) 	case $LINE in
 1) 	    \%\!) echo $file: valid   ;;
 1) 	    *)    echo $file: invalid ;;
 1) 	esac
 1) fi; done

( I've vertically compressed John's code. )

the above will work with any Bourne-ish shell.
however, five nits --- its behavior ...

 ... on empty files is problematic;

 ... on unreadable files is perhaps not what's wanted;

 ... on bizarre filenames (e.g., a file whose name contain
     spaces) is probably undesirable;

 ... on binary files is problematic; and

 ... on other sorts of bizarre filenames (e.g., one whose
     name contains sequences like `\n', i.e., a backslash
     followed by the letter `n'), may produce odd output.

the 4th (binary files) cannot(?) be fixed in pure Bourne-ish-ism,
and I will not address the 5th (\n in filenames); but the first
three are easy --- replace `for'-loop guts with something like:

  answer=invalid
  [ -f "$file" -a -r "$file" ] && read line <"$file" && case $line in
      %!*) answer=valid ;;
  esac
  echo "$file: $answer"

however, as others have mentioned, a better answer is to
use file(1).  (the perl(1) solution someone posted was rather
neat as well.)  if you have GNU `file', you might want to
take a look at the `-i' option, which has the advantage of
outputting predictable text.

 2) Date: Fri, 5 Apr 2002 20:03:30 +0100
 2) From: Niall O Broin <niall at linux.ie>
 2) 
 2) > On April 5, niall at linux.ie said:
 2) > > The line
 2) > > 
 2) > >   if [[ "`file -b $file`" == PostScript\ document\ text* ]] ; then
 2) > > 
 2) > > is some bash magic - [[ str1 == str2 ]] does a pattern match [ ... ]

interesting!  I hadn't realized there was a difference between
the `==' (nee `=') and `!=' operators of the classical `[ ... ]'
(nee test(1)) and `[[ ... ]]' commands (which I also recall was
first added by ksh(1)) --- thanks!

be that as it may, it is a bad habit to write things like:

   [ "$s1" = foo ]

unless the value of $s1 is strictly known to be safe.  (for the
purposes of this discussion, there is no difference between "$s1"
and "`cmd ...`".)  consider what happens if $s1 has the value:

   !

i.e., the single character `!'.  then the test becomes:

   [ ! = foo ]

which, classically, is a syntax error.  having said that,
bash's `[ ... ]' has a complex hierarchy of rules which,
in this case, Do What Is Meant.  the all-Bourne-ish fix:

   [ "X$s1" = Xfoo ]

is so trivial, I see no point to relying on bash to DWIM a
(IMHO) bad habit.   note, b.t.w., if you do want to rely
on using bash, then you might as well use the more readable
$(...) syntax rather than `...`:

   [ "$(file -b "$file")" == ... ]

that syntax --- complete with the ability to nest quotes as
shown --- also first(?) appeared in ksh(1), and is (IMHO)
one of ksh's best features/fixes/changes/improvements over
Bourne's original shell.

cheers!
	-blf-
--
 Innovative, very experienced, Unix and      | Brian Foster    Dublin, Ireland
 Chorus (embedded RTOS) kernel internals     | e-mail: blf at utvinternet.ie
 expert looking for a new position ...       | mobile: (+353 or 0)86 854 9268
  For a resume, contact me, or see my website  http://www.blf.utvinternet.ie




More information about the ILUG mailing list