Bash pipe syntax makes variables local, breaking sendfax scripts

Pilch (ucc02aa@sunmail.lrz-muenchen.de)
Thu, 18 Jan 1996 11:51:54 +0100


BUG/PROBLEM REPORT

PROGRAM:	bash, sendfax
VERSION:	1.14.3(1)
UNAME-A:	Linux oaf84 1.3.20 #16 Sun Oct 15 02:18:27 MET 1995 i486
REPORTER:	Hartmut_Pilch<ucc02aa@sunmail.lrz-muenchen.de>
SUBJECT:	Bash pipe syntax makes variables local, breaking sendfax scripts

Look at this shell dialogue:

<dialog(>

$ unset E;{ frazzle;E=$? }|tee dum;echo errorlevel $E
unset E;{ frazzle;E=$? };echo errorlevel $E
bash: frazzle: command not found
errorlevel 127
$ unset E;{ frazzle;E=$? }|tee dum;echo errorlevel $E
unset E;{ frazzle;E=$? }|tee dum;echo errorlevel $E
bash: frazzle: command not found
errorlevel
$ unset E;{ frazzle;E=$? }|tee dum;echo errorlevels $E and $?
unset E;{ frazzle;E=$? }|tee dum;echo errorlevels $E and $?
bash: frazzle: command not found
errorlevels and 0

<)dialog>

It becomes clear that the `tee' pipe prevents the 
declaration of E from being valid outside the curled bracket.

The tee pipe unfortunately also changes the errorlevel of
everything to 0.  A desirable Bash behavior would be to
end with the first nonzero error code of the pipe chain.

Simple shell scripts like one for sending the remaining
faxpages after an interruption become impossible.
Normally they could look roughly like this (using 
Gert Doering's sendfax program):

<script(>

until test $# -eq 0 || sendfax -v $@ 2>&1 | tee LOGFILE;do
  np=$(grep -c sending $LOGFILE);
  n=1;while test $n -lt $np;do shift;let n=n+1;done;
 done;
 
<)script>

This won't work first of all because of the tee pipe's error
hiding behavior, secondly because there is no way to store 
the error information in a variable.  The only workaround
is to store it in a temporary file, as in the following bulky
script:

<script(>

# begin configuration section
# how to deduct resolution option from filename
resopt () { expr $1 : ".*\.g3\(n\)" } 
# end configuration section

FAXNUM=$1;shift;
R=$(resopt $1);

mysendfax () { local FT=~/.lastsendfaxerrlvl FL=~/.lastsendfaxstderr;{ $SENDFAX -v$R $@;echo $? > $FT } 2>&1 | tee $FL;NP=$(grep -c sending $FL);return $(cat $FT) }

until test $# -eq 0 || mysendfax $FAXNUM $@;do
  n=1;while test $n -lt $NP;do let n=n+1;shift;done
  sleep 1m;
 done;

<)script>

Of course the whole script writing task would become very simple, if
the sendfax program itself could be modified so that it read file
names from and stored the names of the unsent files in an environment
variable such as SENDFAXFILES.  You would then need to write only:

<script(>

FAXNUM=$1;shift;R=$(resopt $1);SENDFAXFILES="$@"
until sendfax $FAXNUM -v$R;do sleep 1m;done

<)script>

But even if all programs were so considerate, I would like a more
powerful shell syntax.