⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 debugging.html

📁 Shall高级编程
💻 HTML
📖 第 1 页 / 共 2 页
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><HTML><HEAD><TITLE>Debugging</TITLE><METANAME="GENERATOR"CONTENT="Modular DocBook HTML Stylesheet Version 1.76b+"><LINKREL="HOME"TITLE="Advanced Bash-Scripting Guide"HREF="index.html"><LINKREL="UP"TITLE="Advanced Topics"HREF="part5.html"><LINKREL="PREVIOUS"TITLE="Of Zeros and Nulls"HREF="zeros.html"><LINKREL="NEXT"TITLE="Options"HREF="options.html"><METAHTTP-EQUIV="Content-Style-Type"CONTENT="text/css"><LINKREL="stylesheet"HREF="common/kde-common.css"TYPE="text/css"><METAHTTP-EQUIV="Content-Type"CONTENT="text/html; charset=iso-8859-1"><METAHTTP-EQUIV="Content-Language"CONTENT="en"><LINKREL="stylesheet"HREF="common/kde-localised.css"TYPE="text/css"TITLE="KDE-English"><LINKREL="stylesheet"HREF="common/kde-default.css"TYPE="text/css"TITLE="KDE-Default"></HEAD><BODYCLASS="CHAPTER"BGCOLOR="#FFFFFF"TEXT="#000000"LINK="#AA0000"VLINK="#AA0055"ALINK="#AA0000"STYLE="font-family: sans-serif;"><DIVCLASS="NAVHEADER"><TABLESUMMARY="Header navigation table"WIDTH="100%"BORDER="0"CELLPADDING="0"CELLSPACING="0"><TR><THCOLSPAN="3"ALIGN="center">Advanced Bash-Scripting Guide: An in-depth exploration of the art of shell scripting</TH></TR><TR><TDWIDTH="10%"ALIGN="left"VALIGN="bottom"><AHREF="zeros.html"ACCESSKEY="P">Prev</A></TD><TDWIDTH="80%"ALIGN="center"VALIGN="bottom"></TD><TDWIDTH="10%"ALIGN="right"VALIGN="bottom"><AHREF="options.html"ACCESSKEY="N">Next</A></TD></TR></TABLE><HRALIGN="LEFT"WIDTH="100%"></DIV><DIVCLASS="CHAPTER"><H1><ANAME="DEBUGGING"></A>Chapter 29. Debugging</H1><TABLEBORDER="0"WIDTH="100%"CELLSPACING="0"CELLPADDING="0"CLASS="EPIGRAPH"><TR><TDWIDTH="45%">&nbsp;</TD><TDWIDTH="45%"ALIGN="LEFT"VALIGN="TOP"><I><P><I>Debugging is twice as hard as writing the code in the first        place. Therefore, if you write the code as cleverly as possible,        you are, by definition, not smart enough to debug it.</I></P><P><I>--Brian Kernighan</I></P></I></TD></TR></TABLE><P>The Bash shell contains no built-in debugger, and only bare-bones	debugging-specific commands and constructs. Syntax errors or	outright typos in the script generate cryptic error messages that	are often of no help in debugging a non-functional script.</P><DIVCLASS="EXAMPLE"><HR><ANAME="EX74"></A><P><B>Example 29-1. A buggy script</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">   1&nbsp;#!/bin/bash   2&nbsp;# ex74.sh   3&nbsp;   4&nbsp;# This is a buggy script.   5&nbsp;# Where, oh where is the error?   6&nbsp;   7&nbsp;a=37   8&nbsp;   9&nbsp;if [$a -gt 27 ]  10&nbsp;then  11&nbsp;  echo $a  12&nbsp;fi    13&nbsp;  14&nbsp;exit 0</PRE></TD></TR></TABLE><HR></DIV><P>Output from script:	<TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="SCREEN"> <TTCLASS="COMPUTEROUTPUT">./ex74.sh: [37: command not found</TT></PRE></TD></TR></TABLE>        What's wrong with the above script? Hint: after the        <ICLASS="FIRSTTERM">if</I>.</P><DIVCLASS="EXAMPLE"><HR><ANAME="MISSINGKEYWORD"></A><P><B>Example 29-2. Missing <AHREF="internal.html#KEYWORDREF">keyword</A></B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">   1&nbsp;#!/bin/bash   2&nbsp;# missing-keyword.sh: What error message will this generate?   3&nbsp;   4&nbsp;for a in 1 2 3   5&nbsp;do   6&nbsp;  echo "$a"   7&nbsp;# done     # Required keyword 'done' commented out in line 7.   8&nbsp;   9&nbsp;exit 0  </PRE></TD></TR></TABLE><HR></DIV><P>Output from script:	<TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="SCREEN"> <TTCLASS="COMPUTEROUTPUT">missing-keyword.sh: line 10: syntax error: unexpected end of file</TT> 	</PRE></TD></TR></TABLE>	Note that the error message does <SPANCLASS="emphasis"><ICLASS="EMPHASIS">not</I></SPAN> necessarily	reference the line in which the error occurs, but the line where the	Bash interpreter finally becomes aware of the error.	</P><P>Error messages may disregard comment lines in a script when        reporting the line number of a syntax error.</P><P>What if the script executes, but does not work as expected? This is the	all too familiar logic error.</P><DIVCLASS="EXAMPLE"><HR><ANAME="EX75"></A><P><B>Example 29-3. <ICLASS="FIRSTTERM">test24</I>: another buggy script</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">   1&nbsp;#!/bin/bash   2&nbsp;   3&nbsp;#  This script is supposed to delete all filenames in current directory   4&nbsp;#+ containing embedded spaces.   5&nbsp;#  It doesn't work.   6&nbsp;#  Why not?   7&nbsp;   8&nbsp;   9&nbsp;badname=`ls | grep ' '`  10&nbsp;  11&nbsp;# Try this:  12&nbsp;# echo "$badname"  13&nbsp;  14&nbsp;rm "$badname"  15&nbsp;  16&nbsp;exit 0</PRE></TD></TR></TABLE><HR></DIV><P>Try to find out what's wrong with <AHREF="debugging.html#EX75">Example 29-3</A>	by uncommenting the <TTCLASS="USERINPUT"><B>echo "$badname"</B></TT> line. Echo	statements are useful for seeing whether what you expect is	actually what you get.</P><P>In this particular case, <TTCLASS="USERINPUT"><B>rm "$badname"</B></TT>	will not give the desired results because	<TTCLASS="VARNAME">$badname</TT> should not be quoted. Placing it	in quotes ensures that <BCLASS="COMMAND">rm</B> has only one	argument (it will match only one filename). A partial fix	is to remove to quotes from <TTCLASS="VARNAME">$badname</TT> and	to reset <TTCLASS="VARNAME">$IFS</TT> to contain only a newline,	<TTCLASS="USERINPUT"><B>IFS=$'\n'</B></TT>. However, there are simpler	ways of going about it.	<TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">   1&nbsp;# Correct methods of deleting filenames containing spaces.   2&nbsp;rm *\ *   3&nbsp;rm *" "*   4&nbsp;rm *' '*   5&nbsp;# Thank you. S.C.</PRE></TD></TR></TABLE>		</P><P>Summarizing the symptoms of a buggy script,	<OLTYPE="1"><LI><P>It bombs with a <SPANCLASS="QUOTE">"<SPANCLASS="ERRORNAME">syntax error</SPAN>"</SPAN> message, or</P></LI><LI><P>It runs, but does not work as expected 	      (<SPANCLASS="ERRORNAME">logic error</SPAN>).</P></LI><LI><P>It runs, works as expected, but has nasty side effects	      (<SPANCLASS="ERRORNAME">logic bomb</SPAN>).</P></LI></OL>      </P><P><ANAME="DEBUGTOOLS"></A></P><P>Tools for debugging non-working scripts include	<OLTYPE="1"><LI><P><AHREF="internal.html#ECHOREF">echo</A> statements at	      critical points in the script to trace the variables,	      and otherwise give a snapshot of what is going on.</P><DIVCLASS="TIP"><TABLECLASS="TIP"WIDTH="90%"BORDER="0"><TR><TDWIDTH="25"ALIGN="CENTER"VALIGN="TOP"><IMGSRC="common/tip.png"HSPACE="5"ALT="Tip"></TD><TDALIGN="LEFT"VALIGN="TOP"><P>Even better is an <BCLASS="COMMAND">echo</B> that echoes	      only when <ICLASS="FIRSTTERM">debug</I> is on.	        <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><PRECLASS="PROGRAMLISTING">   1&nbsp;### debecho (debug-echo), by Stefano Falsetto ###   2&nbsp;### Will echo passed parameters only if DEBUG is set to a value. ###   3&nbsp;debecho () {   4&nbsp;  if [ ! -z "$DEBUG" ]; then   5&nbsp;     echo "$1" &#62;&#38;2   6&nbsp;     #         ^^^ to stderr   7&nbsp;  fi   8&nbsp;}   9&nbsp;  10&nbsp;DEBUG=on  11&nbsp;Whatever=whatnot  12&nbsp;debecho $Whatever   # whatnot  13&nbsp;  14&nbsp;DEBUG=  15&nbsp;Whatever=notwhat  16&nbsp;debecho $Whatever   # (Will not echo.)</PRE></TD></TR></TABLE>            </P></TD></TR></TABLE></DIV></LI><LI><P>using the <AHREF="extmisc.html#TEEREF">tee</A> filter	      to check processes or data flows at critical points.</P></LI><LI><P>setting option flags <TTCLASS="OPTION">-n -v -x</TT></P><P><TTCLASS="USERINPUT"><B>sh -n scriptname</B></TT> checks for	      syntax errors without actually running the script. This is	      the equivalent of inserting <TTCLASS="USERINPUT"><B>set -n</B></TT> or	      <TTCLASS="USERINPUT"><B>set -o noexec</B></TT> into the script. Note	      that certain types of syntax errors can slip past this	      check.</P><P><TTCLASS="USERINPUT"><B>sh -v scriptname</B></TT> echoes each	      command before executing it. This is the equivalent of	      inserting <TTCLASS="USERINPUT"><B>set -v</B></TT> or <TTCLASS="USERINPUT"><B>set	      -o verbose</B></TT> in the script.</P><P>The <TTCLASS="OPTION">-n</TT> and <TTCLASS="OPTION">-v</TT>	      flags work well together. <TTCLASS="USERINPUT"><B>sh -nv	      scriptname</B></TT> gives a verbose syntax check.</P><P><TTCLASS="USERINPUT"><B>sh -x scriptname</B></TT> echoes the result each	      command, but in an abbreviated manner. This is the equivalent of	      inserting <TTCLASS="USERINPUT"><B>set -x</B></TT> or 	      <TTCLASS="USERINPUT"><B>set -o xtrace</B></TT> in the script.</P><P><ANAME="UNDVARERR"></A></P><P>Inserting <TTCLASS="USERINPUT"><B>set -u</B></TT> or 		<TTCLASS="USERINPUT"><B>set -o nounset</B></TT> in the script runs it, but		gives an <SPANCLASS="ERRORNAME">unbound variable</SPAN> error message		at each attempt to use an undeclared variable.</P></LI><LI><P>Using an <SPANCLASS="QUOTE">"assert"</SPAN> function to test a	      variable or condition at critical points in a script. (This is	      an idea borrowed from C.)</P><DIVCLASS="EXAMPLE"><HR><ANAME="ASSERT"></A><P><B>Example 29-4. Testing a condition with an	      <ICLASS="FIRSTTERM">assert</I></B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><PRECLASS="PROGRAMLISTING">   1&nbsp;#!/bin/bash   2&nbsp;# assert.sh   3&nbsp;   4&nbsp;#######################################################################   5&nbsp;assert ()                 #  If condition false,   6&nbsp;{                         #+ exit from script   7&nbsp;                          #+ with appropriate error message.   8&nbsp;  E_PARAM_ERR=98   9&nbsp;  E_ASSERT_FAILED=99  10&nbsp;  11&nbsp;  12&nbsp;  if [ -z "$2" ]          #  Not enough parameters passed  13&nbsp;  then                    #+ to assert() function.  14&nbsp;    return $E_PARAM_ERR   #  No damage done.  15&nbsp;  fi  16&nbsp;  17&nbsp;  lineno=$2  18&nbsp;  19&nbsp;  if [ ! $1 ]   20&nbsp;  then  21&nbsp;    echo "Assertion failed:  \"$1\""  22&nbsp;    echo "File \"$0\", line $lineno"    # Give name of file and line number.  23&nbsp;    exit $E_ASSERT_FAILED  24&nbsp;  # else  25&nbsp;  #   return  26&nbsp;  #   and continue executing the script.  27&nbsp;  fi    28&nbsp;} # Insert a similar assert() function into a script you need to debug.      29&nbsp;#######################################################################  30&nbsp;  31&nbsp;  32&nbsp;a=5  33&nbsp;b=4  34&nbsp;condition="$a -lt $b"     #  Error message and exit from script.  35&nbsp;                          #  Try setting "condition" to something else  36&nbsp;                          #+ and see what happens.  37&nbsp;  38&nbsp;assert "$condition" $LINENO  39&nbsp;# The remainder of the script executes only if the "assert" does not fail.  40&nbsp;  41&nbsp;  42&nbsp;# Some commands.  43&nbsp;# Some more commands . . .  44&nbsp;echo "This statement echoes only if the \"assert\" does not fail."  45&nbsp;# . . .  46&nbsp;# More commands . . .  47&nbsp;  48&nbsp;exit $?</PRE></TD></TR></TABLE><HR></DIV></LI><LI><P>Using the <AHREF="variables2.html#LINENOREF">$LINENO</A>	      variable and the <AHREF="internal.html#CALLERREF">caller</A>	      builtin.</P></LI><LI><P><ANAME="DEBUGTRAP"></A></P><P>trapping at exit.</P><P>The <BCLASS="COMMAND">exit</B> command in a script triggers a	      signal <SPANCLASS="RETURNVALUE">0</SPAN>, terminating the	      process, that is, the script itself.	      <ANAME="AEN17836"HREF="#FTN.AEN17836">[1]</A>	      It is often useful to trap the	      <BCLASS="COMMAND">exit</B>, forcing a <SPANCLASS="QUOTE">"printout"</SPAN>	      of variables, for example. The <BCLASS="COMMAND">trap</B>	      must be the first command in the script.</P></LI></OL>      </P><DIVCLASS="VARIABLELIST"><P

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -