Hi, bash folks, for a larger shell-based project I wanted to have definit answers to questions like
- are all redirections to log handle 3 done when the log handle is actually open? - are all calls to grep handled properly (either return value or output ignored)? - are all calls to exit valid? Parsing shell syntax by means of Perl regexps turned to out to be hard and unreliable. So I added a new bash commandline option '--dump-syntax' that lets bash dump an XML-based syntax tree of the input script. The rest of the job was relatively easy using Perl and Perl-based XPath queries. (As a side-effect, bash also checks the syntax of process and command substitutions, what option "-n" would not do.) And now that I have my bashlint perl script I start getting adicted to it - every time I come across a stupid bug in my code I start thinking how bashlint could have detected that bug. I work for a closed-source software company and I would need extra paperwork to release the (bash-4.0-based) patch under the GPL. I already asked the bash maintainer (who found the idea interesting) and he proposed to ask the bash society for feedback before starting the paperwork. Please let me know what you think. Regards Jens Es weihnachtet sehr! Vom leckerem Backrezept bis zum leckeren Schneehasen finden Sie alles im Weihnachtsspecial von Arcor.de: http://www.arcor.de/rd/footer.weihnachten Feliz Navidad, God Yul, Merry X-Mas und ein frohes Fest!
savelog
Description: Binary data
<?xml version="1.0" encoding="iso-8859-1"?> <script> <simple line="81"> <w text="export"/> <w text="PATH=$PATH:/sbin:/bin:/usr/sbin:/usr/bin"/> </simple> <simple line="82"> <a name="COMPRESS" text=""gzip""/> </simple> <simple line="83"> <a name="COMPRESS_OPTS" text=""-9f""/> </simple> <simple line="84"> <a name="DOT_Z" text="".gz""/> </simple> <simple line="85"> <a name="DATUM" text="`date +%Y%m%d%H%M%S`"> <simple line="1"> <w text="date"/> <w text="+%Y%m%d%H%M%S"/> </simple> </a> </simple> <simple line="88"> <a name="exitcode" text="0"/> </simple> <simple line="89"> <a name="prog" text="`basename $0`"> <simple line="1"> <w text="basename"/> <w text="$0"/> </simple> </a> </simple> <simple line="90"> <a name="mode" text=""/> </simple> <simple line="91"> <a name="user" text=""/> </simple> <simple line="92"> <a name="group" text=""/> </simple> <simple line="93"> <a name="touch" text=""/> </simple> <simple line="94"> <a name="forceclean" text=""/> </simple> <simple line="95"> <a name="rolldir" text=""/> </simple> <simple line="96"> <a name="datum" text=""/> </simple> <simple line="97"> <a name="preserve" text=""/> </simple> <simple line="98"> <a name="hookscript" text=""/> </simple> <simple line="99"> <a name="quiet" text="0"/> </simple> <simple line="100"> <a name="rotateifempty" text="yes"/> </simple> <simple line="101"> <a name="count" text="7"/> </simple> <function> <funcname> <w text="usage"/> </funcname> <funcbody> <group> <seq> <simple line="105"> <w text="echo"/> <w text=""Usage: $prog [-m mode] [-u user] [-g group] [-t] [-c cycle] [-p]""/> </simple> <simple line="106"> <w text="echo"/> <w text="" [-j] [-C] [-d] [-l] [-r rolldir] [-n] [-q] file ...""/> </simple> <simple line="107"> <w text="echo"/> <w text="" -m mode - chmod log files to mode""/> </simple> <simple line="108"> <w text="echo"/> <w text="" -u user - chown log files to user""/> </simple> <simple line="109"> <w text="echo"/> <w text="" -g group - chgrp log files to group""/> </simple> <simple line="110"> <w text="echo"/> <w text="" -c cycle - save cycle versions of the logfile (default: 7)""/> </simple> <simple line="111"> <w text="echo"/> <w text="" -r rolldir - use rolldir instead of . to roll files""/> </simple> <simple line="112"> <w text="echo"/> <w text="" -C - force cleanup of cycled logfiles""/> </simple> <simple line="113"> <w text="echo"/> <w text="" -d - use standard date for rolling""/> </simple> <simple line="114"> <w text="echo"/> <w text="" -D - override date format for -d""/> </simple> <simple line="115"> <w text="echo"/> <w text="" -t - touch file""/> </simple> <simple line="116"> <w text="echo"/> <w text="" -l - don't compress any log files (default: compress)""/> </simple> <simple line="117"> <w text="echo"/> <w text="" -p - preserve mode/user/group of original file""/> </simple> <simple line="118"> <w text="echo"/> <w text="" -j - use bzip2 instead of gzip""/> </simple> <simple line="119"> <w text="echo"/> <w text="" -x script - invoke script with rotated log file in \$FILE""/> </simple> <simple line="120"> <w text="echo"/> <w text="" -n - do not rotate empty files""/> </simple> <simple line="121"> <w text="echo"/> <w text="" -q - suppress rotation message""/> </simple> <simple line="122"> <w text="echo"/> <w text="" file - log file names""/> </simple> </seq> </group> </funcbody> </function> <function> <funcname> <w text="fixfile"/> </funcname> <funcbody> <group> <seq> <if> <ifcond> <simple line="128"> <w text="["/> <w text="-n"/> <w text=""$user""/> <w text="]"/> </simple> </ifcond> <ifthen> <simple line="129"> <w text="chown"/> <w text="--"/> <w text=""$user""/> <w text=""$1""/> </simple> </ifthen> </if> <if> <ifcond> <simple line="131"> <w text="["/> <w text="-n"/> <w text=""$group""/> <w text="]"/> </simple> </ifcond> <ifthen> <simple line="132"> <w text="chgrp"/> <w text="--"/> <w text=""$group""/> <w text=""$1""/> </simple> </ifthen> </if> <if> <ifcond> <simple line="134"> <w text="["/> <w text="-n"/> <w text=""$mode""/> <w text="]"/> </simple> </ifcond> <ifthen> <simple line="135"> <w text="chmod"/> <w text="--"/> <w text=""$mode""/> <w text=""$1""/> </simple> </ifthen> </if> </seq> </group> </funcbody> </function> <while> <loopcond> <simple line="140"> <w text="getopts"/> <w text="m:u:g:c:r:CdD:tlphjx:nq"/> <w text="opt"/> </simple> </loopcond> <loopbody> <case> <caseword> <w text=""$opt""/> </caseword> <casetest> <w text="m"/> </casetest> <casebody> <simple line="142"> <a name="mode" text=""$OPTARG""/> </simple> </casebody> <casetest> <w text="u"/> </casetest> <casebody> <simple line="143"> <a name="user" text=""$OPTARG""/> </simple> </casebody> <casetest> <w text="g"/> </casetest> <casebody> <simple line="144"> <a name="group" text=""$OPTARG""/> </simple> </casebody> <casetest> <w text="c"/> </casetest> <casebody> <simple line="145"> <a name="count" text=""$OPTARG""/> </simple> </casebody> <casetest> <w text="r"/> </casetest> <casebody> <simple line="146"> <a name="rolldir" text=""$OPTARG""/> </simple> </casebody> <casetest> <w text="C"/> </casetest> <casebody> <simple line="147"> <a name="forceclean" text="1"/> </simple> </casebody> <casetest> <w text="d"/> </casetest> <casebody> <simple line="148"> <a name="datum" text="1"/> </simple> </casebody> <casetest> <w text="D"/> </casetest> <casebody> <simple line="149"> <a name="DATUM" text="$(date +$OPTARG)"> <simple line="1"> <w text="date"/> <w text="+$OPTARG"/> </simple> </a> </simple> </casebody> <casetest> <w text="t"/> </casetest> <casebody> <simple line="150"> <a name="touch" text="1"/> </simple> </casebody> <casetest> <w text="j"/> </casetest> <casebody> <seq> <simple line="151"> <a name="COMPRESS" text=""bzip2""/> </simple> <simple line="151"> <a name="COMPRESS_OPTS" text=""-9f""/> </simple> <simple line="151"> <a name="DOT_Z" text="".bz2""/> </simple> </seq> </casebody> <casetest> <w text="x"/> </casetest> <casebody> <simple line="152"> <a name="hookscript" text=""$OPTARG""/> </simple> </casebody> <casetest> <w text="l"/> </casetest> <casebody> <simple line="153"> <a name="COMPRESS" text=""""/> </simple> </casebody> <casetest> <w text="p"/> </casetest> <casebody> <simple line="154"> <a name="preserve" text="1"/> </simple> </casebody> <casetest> <w text="n"/> </casetest> <casebody> <simple line="155"> <a name="rotateifempty" text=""no""/> </simple> </casebody> <casetest> <w text="q"/> </casetest> <casebody> <simple line="156"> <a name="quiet" text="1"/> </simple> </casebody> <casetest> <w text="h"/> </casetest> <casebody> <seq> <simple line="157"> <w text="usage"/> </simple> <simple line="157"> <w text="exit"/> <w text="0"/> </simple> </seq> </casebody> <casetest> <w text="*"/> </casetest> <casebody> <seq> <simple line="158"> <w text="usage"/> </simple> <simple line="158"> <w text="exit"/> <w text="1"/> </simple> </seq> </casebody> </case> </loopbody> </while> <simple line="162"> <w text="shift"/> <w text="$(($OPTIND - 1))"/> </simple> <if> <ifcond> <simple line="164"> <w text="["/> <w text=""$count""/> <w text="-lt"/> <w text="2"/> <w text="]"/> </simple> </ifcond> <ifthen> <seq> <simple line="165"> <w text="echo"/> <w text=""$prog: count must be at least 2""/> <redirect type="dupout" from="1" to="2"/> </simple> <simple line="166"> <w text="exit"/> <w text="2"/> </simple> </seq> </ifthen> </if> <if> <ifcond> <and> <simple line="169"> <w text="["/> <w text="-n"/> <w text=""$COMPRESS""/> <w text="]"/> </simple> <simple line="169"> <w text="["/> <w text="-z"/> <w text=""`which $COMPRESS`""> <simple line="1"> <w text="which"/> <w text="$COMPRESS"/> </simple> </w> <w text="]"/> </simple> </and> </ifcond> <ifthen> <seq> <simple line="170"> <w text="echo"/> <w text=""$prog: Compression binary not available, please make sure '$COMPRESS' is installed""/> <redirect type="dupout" from="1" to="2"/> </simple> <simple line="171"> <w text="exit"/> <w text="2"/> </simple> </seq> </ifthen> </if> <while> <loopcond> <simple line="175"> <w text="["/> <w text="$#"/> <w text="-gt"/> <w text="0"/> <w text="]"/> </simple> </loopcond> <loopbody> <seq> <simple line="178"> <a name="filename" text=""$1""/> </simple> <simple line="179"> <w text="shift"/> </simple> <if> <ifcond> <and> <simple line="182"> <w text="["/> <w text="-e"/> <w text=""$filename""/> <w text="]"/> </simple> <simple line="182"> <w text="["/> <w text="!"/> <w text="-f"/> <w text=""$filename""/> <w text="]"/> </simple> </and> </ifcond> <ifthen> <seq> <simple line="183"> <w text="echo"/> <w text=""$prog: $filename is not a regular file""/> <redirect type="dupout" from="1" to="2"/> </simple> <simple line="184"> <a name="exitcode" text="3"/> </simple> <simple line="185"> <w text="continue"/> </simple> </seq> </ifthen> </if> <if> <ifcond> <and> <simple line="190"> <w text="["/> <w text="!"/> <w text="-s"/> <w text=""$filename""/> <w text="]"/> </simple> <simple line="190"> <w text="["/> <w text=""$rotateifempty""/> <w text="!="/> <w text=""yes""/> <w text="]"/> </simple> </and> </ifcond> <ifthen> <seq> <if> <ifcond> <and> <simple line="192"> <w text="test"/> <w text="-n"/> <w text=""$touch""/> </simple> <simple line="192"> <w text="["/> <w text="!"/> <w text="-f"/> <w text=""$filename""/> <w text="]"/> </simple> </and> </ifcond> <ifthen> <seq> <simple line="193"> <w text="touch"/> <w text="--"/> <w text=""$filename""/> </simple> <if> <ifcond> <simple line="194"> <w text="["/> <w text=""$?""/> <w text="-ne"/> <w text="0"/> <w text="]"/> </simple> </ifcond> <ifthen> <seq> <simple line="195"> <w text="echo"/> <w text=""$prog: could not touch $filename""/> <redirect type="dupout" from="1" to="2"/> </simple> <simple line="196"> <a name="exitcode" text="4"/> </simple> <simple line="197"> <w text="continue"/> </simple> </seq> </ifthen> </if> <simple line="199"> <w text="fixfile"/> <w text=""$filename""/> </simple> </seq> </ifthen> </if> <simple line="201"> <w text="continue"/> </simple> </seq> </ifthen> </if> <simple line="206"> <a name="savedir" text="`dirname -- "$filename"`"> <simple line="1"> <w text="dirname"/> <w text="--"/> <w text=""$filename""/> </simple> </a> </simple> <if> <ifcond> <simple line="207"> <w text="["/> <w text="-z"/> <w text=""$savedir""/> <w text="]"/> </simple> </ifcond> <ifthen> <simple line="208"> <a name="savedir" text="."/> </simple> </ifthen> </if> <case> <caseword> <w text=""$rolldir""/> </caseword> <casetest> <w text="/*"/> </casetest> <casebody> <simple line="212"> <a name="savedir" text=""$rolldir""/> </simple> </casebody> <casetest> <w text="*"/> </casetest> <casebody> <simple line="215"> <a name="savedir" text=""$savedir/$rolldir""/> </simple> </casebody> </case> <if> <ifcond> <simple line="218"> <w text="["/> <w text="!"/> <w text="-d"/> <w text=""$savedir""/> <w text="]"/> </simple> </ifcond> <ifthen> <seq> <simple line="219"> <w text="mkdir"/> <w text="-p"/> <w text="--"/> <w text=""$savedir""/> </simple> <if> <ifcond> <simple line="220"> <w text="["/> <w text=""$?""/> <w text="-ne"/> <w text="0"/> <w text="]"/> </simple> </ifcond> <ifthen> <seq> <simple line="221"> <w text="echo"/> <w text=""$prog: could not mkdir $savedir""/> <redirect type="dupout" from="1" to="2"/> </simple> <simple line="222"> <a name="exitcode" text="5"/> </simple> <simple line="223"> <w text="continue"/> </simple> </seq> </ifthen> </if> <simple line="225"> <w text="chmod"/> <w text="0755"/> <w text="--"/> <w text=""$savedir""/> </simple> </seq> </ifthen> </if> <if> <ifcond> <simple line="227"> <w text="["/> <w text="!"/> <w text="-w"/> <w text=""$savedir""/> <w text="]"/> </simple> </ifcond> <ifthen> <seq> <simple line="228"> <w text="echo"/> <w text=""$prog: directory $savedir is not writable""/> <redirect type="dupout" from="1" to="2"/> </simple> <simple line="229"> <a name="exitcode" text="7"/> </simple> <simple line="230"> <w text="continue"/> </simple> </seq> </ifthen> </if> <simple line="234"> <a name="newname" text="`basename -- "$filename"`"> <simple line="1"> <w text="basename"/> <w text="--"/> <w text=""$filename""/> </simple> </a> </simple> <simple line="235"> <a name="newname" text=""$savedir/$newname""/> </simple> <simple line="238"> <a name="cycle" text="$(( $count - 1))"/> </simple> <simple line="239"> <w text="rm"/> <w text="-f"/> <w text="--"/> <w text=""$newname.$cycle""/> <w text=""$newname.$cycle$DOT_Z""/> </simple> <while> <loopcond> <simple line="240"> <w text="["/> <w text="$cycle"/> <w text="-gt"/> <w text="1"/> <w text="]"/> </simple> </loopcond> <loopbody> <seq> <simple line="242"> <a name="oldcycle" text="$cycle"/> </simple> <simple line="243"> <a name="cycle" text="$(( $cycle - 1 ))"/> </simple> <if> <ifcond> <simple line="245"> <w text="["/> <w text="-f"/> <w text=""$newname.$cycle$DOT_Z""/> <w text="]"/> </simple> </ifcond> <ifthen> <simple line="246"> <w text="mv"/> <w text="-f"/> <w text="--"/> <w text=""$newname.$cycle$DOT_Z""/> <w text=""$newname.$oldcycle$DOT_Z""/> </simple> </ifthen> </if> <if> <ifcond> <simple line="249"> <w text="["/> <w text="-f"/> <w text=""$newname.$cycle""/> <w text="]"/> </simple> </ifcond> <ifthen> <simple line="251"> <w text="mv"/> <w text="-f"/> <w text="--"/> <w text=""$newname.$cycle""/> <w text=""$newname.$oldcycle""/> </simple> </ifthen> </if> </seq> </loopbody> </while> <if> <ifcond> <simple line="256"> <w text="["/> <w text="-f"/> <w text=""$newname.0""/> <w text="]"/> </simple> </ifcond> <ifthen> <seq> <if> <ifcond> <simple line="257"> <w text="["/> <w text="-z"/> <w text=""$COMPRESS""/> <w text="]"/> </simple> </ifcond> <ifthen> <seq> <simple line="258"> <a name="newfile" text=""$newname.1""/> </simple> <simple line="259"> <w text="mv"/> <w text="--"/> <w text=""$newname.0""/> <w text=""$newfile""/> </simple> </seq> </ifthen> <ifelse> <seq> <simple line="261"> <a name="newfile" text=""$newname.1$DOT_Z""/> </simple> <simple line="264"> <w text="$COMPRESS"/> <w text="$COMPRESS_OPTS"/> <w text=""$newname.0""/> </simple> <simple line="265"> <w text="mv"/> <w text="--"/> <w text=""$newname.0$DOT_Z""/> <w text=""$newfile""/> </simple> </seq> </ifelse> </if> <simple line="267"> <w text="fixfile"/> <w text=""$newfile""/> </simple> </seq> </ifthen> </if> <if> <ifcond> <and> <simple line="271"> <w text="test"/> <w text="-n"/> <w text=""$datum""/> </simple> <simple line="271"> <w text="test"/> <w text="-n"/> <w text=""$COMPRESS""/> </simple> </and> </ifcond> <ifthen> <simple line="272"> <w text="$COMPRESS"/> <w text="$COMPRESS_OPTS"/> <w text="--"/> <w text=""$newname".[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]"/> </simple> </ifthen> </if> <if> <ifcond> <simple line="276"> <w text="["/> <w text="-n"/> <w text=""$forceclean""/> <w text="]"/> </simple> </ifcond> <ifthen> <seq> <simple line="277"> <a name="cycle" text="$(( $count - 1))"/> </simple> <if> <ifcond> <simple line="278"> <w text="["/> <w text="-z"/> <w text=""$COMPRESS""/> <w text="]"/> </simple> </ifcond> <ifthen> <simple line="279"> <w text="rm"/> <w text="-f"/> <w text="--"/> <w text="`ls -t -- $newname.[0-9]* | sed -e 1,${cycle}d`"> <pipe> <simple line="1"> <w text="ls"/> <w text="-t"/> <w text="--"/> <w text="$newname.[0-9]*"/> </simple> <simple line="1"> <w text="sed"/> <w text="-e"/> <w text="1,${cycle}d"/> </simple> </pipe> </w> </simple> </ifthen> <ifelse> <simple line="281"> <w text="rm"/> <w text="-f"/> <w text="--"/> <w text="`ls -t -- $newname.[0-9]*$DOT_Z | sed -e 1,${cycle}d`"> <pipe> <simple line="1"> <w text="ls"/> <w text="-t"/> <w text="--"/> <w text="$newname.[0-9]*$DOT_Z"/> </simple> <simple line="1"> <w text="sed"/> <w text="-e"/> <w text="1,${cycle}d"/> </simple> </pipe> </w> </simple> </ifelse> </if> </seq> </ifthen> </if> <if> <ifcond> <simple line="286"> <w text="["/> <w text="-n"/> <w text=""$preserve""/> <w text="]"/> </simple> </ifcond> <ifthen> <seq> <sub> <seq> <simple line="287"> <w text="umask"/> <w text="077"/> </simple> <simple line="288"> <w text="touch"/> <w text="--"/> <w text=""$filename.new""/> </simple> <simple line="289"> <w text="chown"/> <w text="--reference="$filename""/> <w text="--"/> <w text=""$filename.new""/> </simple> <simple line="290"> <w text="chmod"/> <w text="--reference="$filename""/> <w text="--"/> <w text=""$filename.new""/> </simple> </seq> </sub> <simple line="291"> <a name="filenew" text="1"/> </simple> </seq> </ifthen> <ifcond> <simple line="292"> <w text="["/> <w text="-n"/> <w text=""$touch$user$group$mode""/> <w text="]"/> </simple> </ifcond> <ifthen> <seq> <simple line="293"> <w text="touch"/> <w text="--"/> <w text=""$filename.new""/> </simple> <simple line="294"> <w text="fixfile"/> <w text=""$filename.new""/> </simple> <simple line="295"> <a name="filenew" text="1"/> </simple> </seq> </ifthen> </if> <simple line="298"> <a name="newfilename" text=""$newname.0""/> </simple> <if> <ifcond> <simple line="300"> <w text="["/> <w text="-f"/> <w text=""$filename""/> <w text="]"/> </simple> </ifcond> <ifthen> <if> <ifcond> <simple line="301"> <w text="["/> <w text="-n"/> <w text=""$filenew""/> <w text="]"/> </simple> </ifcond> <ifthen> <if> <ifcond> <simple line="302"> <w text="ln"/> <w text="-f"/> <w text="--"/> <w text=""$filename""/> <w text=""$newfilename""/> </simple> </ifcond> <ifthen> <simple line="303"> <w text="mv"/> <w text="--"/> <w text=""$filename.new""/> <w text=""$filename""/> </simple> </ifthen> <ifelse> <seq> <simple line="305"> <w text="echo"/> <w text=""Error hardlinking $filename to $newfilename""/> <redirect type="dupout" from="1" to="2"/> </simple> <simple line="306"> <a name="exitcode" text="8"/> </simple> <simple line="307"> <w text="continue"/> </simple> </seq> </ifelse> </if> </ifthen> <ifelse> <simple line="310"> <w text="mv"/> <w text="--"/> <w text=""$filename""/> <w text=""$newfilename""/> </simple> </ifelse> </if> </ifthen> </if> <and> <simple line="313"> <w text="["/> <w text="!"/> <w text="-f"/> <w text=""$newfilename""/> <w text="]"/> </simple> <simple line="313"> <w text="touch"/> <w text="--"/> <w text=""$newfilename""/> </simple> </and> <simple line="314"> <w text="fixfile"/> <w text=""$newfilename""/> </simple> <if> <ifcond> <simple line="315"> <w text="["/> <w text="-n"/> <w text=""$datum""/> <w text="]"/> </simple> </ifcond> <ifthen> <seq> <simple line="316"> <w text="mv"/> <w text="--"/> <w text=""$newfilename""/> <w text=""$newname.$DATUM""/> </simple> <simple line="317"> <a name="newfilename" text=""$newname.$DATUM""/> </simple> </seq> </ifthen> </if> <if> <ifcond> <simple line="320"> <w text="["/> <w text="-n"/> <w text=""$hookscript""/> <w text="]"/> </simple> </ifcond> <ifthen> <or> <simple line="321"> <a name="FILE" text=""$newfilename""/> <w text="$SHELL"/> <w text="-c"/> <w text=""$hookscript""/> </simple> <group> <seq> <simple line="323"> <a name="ret" text="$?"/> </simple> <or> <simple line="324"> <w text="test"/> <w text=""$quiet""/> <w text="-eq"/> <w text="1"/> </simple> <simple line="324"> <w text="echo"/> <w text=""Hook script failed with exit code $ret.""/> <redirect type="dupout" from="1" to="2"/> </simple> </or> </seq> </group> </or> </ifthen> </if> <or> <simple line="329"> <w text="test"/> <w text=""$quiet""/> <w text="-eq"/> <w text="1"/> </simple> <simple line="329"> <w text="echo"/> <w text=""Rotated \`$filename' at `date`.""> <simple line="1"> <w text="date"/> </simple> </w> </simple> </or> </seq> </loopbody> </while> <simple line="331"> <w text="exit"/> <w text="$exitcode"/> </simple> </script>