📄 gotchas.html
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><HTML><HEAD><TITLE>Gotchas</TITLE><METANAME="GENERATOR"CONTENT="Modular DocBook HTML Stylesheet Version 1.57"><LINKREL="HOME"TITLE="Advanced Bash-Scripting Guide"HREF="index.html"><LINKREL="UP"TITLE="Advanced Topics"HREF="part4.html"><LINKREL="PREVIOUS"TITLE="Options"HREF="options.html"><LINKREL="NEXT"TITLE="Scripting With Style"HREF="scrstyle.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"><TABLEWIDTH="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="options.html">Prev</A></TD><TDWIDTH="80%"ALIGN="center"VALIGN="bottom"></TD><TDWIDTH="10%"ALIGN="right"VALIGN="bottom"><AHREF="scrstyle.html">Next</A></TD></TR></TABLE><HRALIGN="LEFT"WIDTH="100%"></DIV><DIVCLASS="CHAPTER"><H1><ANAME="GOTCHAS">Chapter 31. Gotchas</A></H1><TABLEBORDER="0"WIDTH="100%"CELLSPACING="0"CELLPADDING="0"CLASS="EPIGRAPH"><TR><TDWIDTH="45%"> </TD><TDWIDTH="45%"ALIGN="LEFT"VALIGN="TOP"><I><P><I>Turandot: Gli enigmi sono tre, la morte una!</I></P><P><I>Caleph: No, no! Gli enigmi sono tre, una la vita!</I></P></I></TD></TR><TR><TDWIDTH="45%"> </TD><TDWIDTH="45%"ALIGN="RIGHT"VALIGN="TOP"><I><SPANCLASS="ATTRIBUTION">Puccini</SPAN></I></TD></TR></TABLE><P><ANAME="BASH3GOTCHA"></A></P><P>Assigning reserved words or characters to variable names. <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> 1 case=value0 # Causes problems. 2 23skidoo=value1 # Also problems. 3 # Variable names starting with a digit are reserved by the shell. 4 # Try _23skidoo=value1. Starting variables with an underscore is o.k. 5 6 # However . . . using just the underscore will not work. 7 _=25 8 echo $_ # $_ is a special variable set to last arg of last command. 9 10 xyz((!*=value2 # Causes severe problems. 11 # As of version 3 of Bash, periods are not allowed within variable names.</PRE></TD></TR></TABLE> </P><P>Using a hyphen or other reserved characters in a variable name (or function name). <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> 1 var-1=23 2 # Use 'var_1' instead. 3 4 function-whatever () # Error 5 # Use 'function_whatever ()' instead. 6 7 8 # As of version 3 of Bash, periods are not allowed within function names. 9 function.whatever () # Error 10 # Use 'functionWhatever ()' instead.</PRE></TD></TR></TABLE> </P><P>Using the same name for a variable and a function. This can make a script difficult to understand. <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> 1 do_something () 2 { 3 echo "This function does something with \"$1\"." 4 } 5 6 do_something=do_something 7 8 do_something do_something 9 10 # All this is legal, but highly confusing.</PRE></TD></TR></TABLE> </P><P><ANAME="WSBAD"></A>Using <AHREF="special-chars.html#WHITESPACEREF">whitespace</A> inappropriately. In contrast to other programming languages, Bash can be quite finicky about whitespace. <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> 1 var1 = 23 # 'var1=23' is correct. 2 # On line above, Bash attempts to execute command "var1" 3 # with the arguments "=" and "23". 4 5 let c = $a - $b # 'let c=$a-$b' or 'let "c = $a - $b"' are correct. 6 7 if [ $a -le 5] # if [ $a -le 5 ] is correct. 8 # if [ "$a" -le 5 ] is even better. 9 # [[ $a -le 5 ]] also works.</PRE></TD></TR></TABLE> </P><P> Assuming uninitialized variables (variables before a value is assigned to them) are <SPANCLASS="QUOTE">"zeroed out"</SPAN>. An uninitialized variable has a value of <SPANCLASS="QUOTE">"null"</SPAN>, <ICLASS="EMPHASIS">not</I> zero. <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 3 echo "uninitialized_var = $uninitialized_var" 4 # uninitialized_var =</PRE></TD></TR></TABLE> </P><P>Mixing up <ICLASS="EMPHASIS">=</I> and <ICLASS="EMPHASIS">-eq</I> in a test. Remember, <ICLASS="EMPHASIS">=</I> is for comparing literal variables and <ICLASS="EMPHASIS">-eq</I> for integers. <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> 1 if [ "$a" = 273 ] # Is $a an integer or string? 2 if [ "$a" -eq 273 ] # If $a is an integer. 3 4 # Sometimes you can mix up -eq and = without adverse consequences. 5 # However . . . 6 7 8 a=273.0 # Not an integer. 9 10 if [ "$a" = 273 ] 11 then 12 echo "Comparison works." 13 else 14 echo "Comparison does not work." 15 fi # Comparison does not work. 16 17 # Same with a=" 273" and a="0273". 18 19 20 # Likewise, problems trying to use "-eq" with non-integer values. 21 22 if [ "$a" -eq 273.0 ] 23 then 24 echo "a = $a" 25 fi # Aborts with an error message. 26 # test.sh: [: 273.0: integer expression expected</PRE></TD></TR></TABLE> </P><P>Misusing <AHREF="comparison-ops.html#SCOMPARISON1">string comparison</A> operators.</P><DIVCLASS="EXAMPLE"><HR><ANAME="BADOP"></A><P><B>Example 31-1. Numerical and string comparison are not equivalent</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # bad-op.sh: Trying to use a string comparison on integers. 3 4 echo 5 number=1 6 7 # The following "while loop" has two errors: 8 #+ one blatant, and the other subtle. 9 10 while [ "$number" < 5 ] # Wrong! Should be: while [ "$number" -lt 5 ] 11 do 12 echo -n "$number " 13 let "number += 1" 14 done 15 # Attempt to run this bombs with the error message: 16 #+ bad-op.sh: line 10: 5: No such file or directory 17 # Within single brackets, "<" must be escaped, 18 #+ and even then, it's still wrong for comparing integers. 19 20 21 echo "---------------------" 22 23 24 while [ "$number" \< 5 ] # 1 2 3 4 25 do # 26 echo -n "$number " # This *seems to work, but . . . 27 let "number += 1" #+ it actually does an ASCII comparison, 28 done #+ rather than a numerical one. 29 30 echo; echo "---------------------" 31 32 # This can cause problems. For example: 33 34 lesser=5 35 greater=105 36 37 if [ "$greater" \< "$lesser" ] 38 then 39 echo "$greater is less than $lesser" 40 fi # 105 is less than 5 41 # In fact, "105" actually is less than "5" 42 #+ in a string comparison (ASCII sort order). 43 44 echo 45 46 exit 0</PRE></TD></TR></TABLE><HR></DIV><P>Sometimes variables within <SPANCLASS="QUOTE">"test"</SPAN> brackets ([ ]) need to be quoted (double quotes). Failure to do so may cause unexpected behavior. See <AHREF="comparison-ops.html#STRTEST">Example 7-6</A>, <AHREF="redircb.html#REDIR2">Example 16-5</A>, and <AHREF="variables2.html#ARGLIST">Example 9-6</A>.</P><P>Commands issued from a script may fail to execute because the script owner lacks execute permission for them. If a user cannot invoke a command from the command line, then putting it into a script will likewise fail. Try changing the attributes of the command in question, perhaps even setting the suid bit (as root, of course).</P><P>Attempting to use <BCLASS="COMMAND">-</B> as a redirection operator (which it is not) will usually result in an unpleasant surprise. <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> 1 command1 2> - | command2 # Trying to redirect error output of command1 into a pipe... 2 # ...will not work. 3 4 command1 2>& - | command2 # Also futile. 5 6 Thanks, S.C.</PRE></TD></TR></TABLE></P><P>Using Bash <AHREF="bash2.html#BASH2REF">version 2+</A> functionality may cause a bailout with error messages. Older Linux machines may have version 1.XX of Bash as the default installation. <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 3 minimum_version=2 4 # Since Chet Ramey is constantly adding features to Bash, 5 # you may set $minimum_version to 2.XX, or whatever is appropriate. 6 E_BAD_VERSION=80 7 8 if [ "$BASH_VERSION" \< "$minimum_version" ] 9 then 10 echo "This script works only with Bash, version $minimum or greater." 11 echo "Upgrade strongly recommended." 12 exit $E_BAD_VERSION 13 fi 14 15 ...</PRE></TD></TR></TABLE></P><P>Using Bash-specific functionality in a Bourne shell script (<TTCLASS="USERINPUT"><B>#!/bin/sh</B></TT>) on a non-Linux machine may cause unexpected behavior. A Linux system usually aliases <BCLASS="COMMAND">sh</B> to <BCLASS="COMMAND">bash</B>, but this does not necessarily hold true for a generic UNIX machine.</P><P>Using undocumented features in Bash turns out to be a dangerous practice. In previous releases of this book there were several scripts that depended on the <SPANCLASS="QUOTE">"feature"</SPAN> that, although the maximum value of an <AHREF="exit-status.html#EXITSTATUSREF">exit</A> or <AHREF="functions.html#RETURNREF">return</A> value was 255, that limit did not apply to <ICLASS="EMPHASIS">negative</I> integers. Unfortunately, in version 2.05b and later, that loophole disappeared. See <AHREF="functions.html#RETURNTEST">Example 23-9</A>.</P><P> A script with DOS-type newlines (<TTCLASS="REPLACEABLE"><I>\r\n</I></TT>) will fail to execute, since <TTCLASS="USERINPUT"><B>#!/bin/bash\r\n</B></TT> is not recognized, <ICLASS="EMPHASIS">not</I> the same as the expected <TTCLASS="USERINPUT"><B>#!/bin/bash\n</B></TT>. The fix is to convert the script to UNIX-style newlines. <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 3 echo "Here" 4 5 unix2dos $0 # Script changes itself to DOS format.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -