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

📄 loops.html

📁 Shall高级编程
💻 HTML
📖 第 1 页 / 共 3 页
字号:
  16&nbsp;exit 0</PRE></TD></TR></TABLE><HR></DIV><P><ANAME="LOOPCS"></A></P><P>It is possible to use <AHREF="commandsub.html#COMMANDSUBREF">command substitution</A>	      to generate the <TTCLASS="USERINPUT"><B>[list]</B></TT> in a	      <ICLASS="FIRSTTERM">for loop</I>. See also <AHREF="extmisc.html#EX53">Example 15-52</A>,	      <AHREF="loops.html#SYMLINKS">Example 10-10</A> and <AHREF="mathc.html#BASE">Example 15-46</A>.</P><DIVCLASS="EXAMPLE"><HR><ANAME="FORLOOPCMD"></A><P><B>Example 10-6. Generating the <TTCLASS="USERINPUT"><B>[list]</B></TT> in	      a <ICLASS="FIRSTTERM">for</I> loop with command substitution</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><PRECLASS="PROGRAMLISTING">   1&nbsp;#!/bin/bash   2&nbsp;#  for-loopcmd.sh: for-loop with [list]   3&nbsp;#+ generated by command substitution.   4&nbsp;   5&nbsp;NUMBERS="9 7 3 8 37.53"   6&nbsp;   7&nbsp;for number in `echo $NUMBERS`  # for number in 9 7 3 8 37.53   8&nbsp;do   9&nbsp;  echo -n "$number "  10&nbsp;done  11&nbsp;  12&nbsp;echo   13&nbsp;exit 0</PRE></TD></TR></TABLE><HR></DIV><P>Here is a somewhat more complex example of using command	      substitution to create the <TTCLASS="USERINPUT"><B>[list]</B></TT>.</P><DIVCLASS="EXAMPLE"><HR><ANAME="BINGREP"></A><P><B>Example 10-7. A <ICLASS="FIRSTTERM">grep</I> replacement	        for binary files</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><PRECLASS="PROGRAMLISTING">   1&nbsp;#!/bin/bash   2&nbsp;# bin-grep.sh: Locates matching strings in a binary file.   3&nbsp;   4&nbsp;# A "grep" replacement for binary files.   5&nbsp;# Similar effect to "grep -a"   6&nbsp;   7&nbsp;E_BADARGS=65   8&nbsp;E_NOFILE=66   9&nbsp;  10&nbsp;if [ $# -ne 2 ]  11&nbsp;then  12&nbsp;  echo "Usage: `basename $0` search_string filename"  13&nbsp;  exit $E_BADARGS  14&nbsp;fi  15&nbsp;  16&nbsp;if [ ! -f "$2" ]  17&nbsp;then  18&nbsp;  echo "File \"$2\" does not exist."  19&nbsp;  exit $E_NOFILE  20&nbsp;fi    21&nbsp;  22&nbsp;  23&nbsp;IFS=$'\012'       # Per suggestion of Anton Filippov.  24&nbsp;                  # was:  IFS="\n"  25&nbsp;for word in $( strings "$2" | grep "$1" )  26&nbsp;# The "strings" command lists strings in binary files.  27&nbsp;# Output then piped to "grep", which tests for desired string.  28&nbsp;do  29&nbsp;  echo $word  30&nbsp;done  31&nbsp;  32&nbsp;# As S.C. points out, lines 23 - 30 could be replaced with the simpler  33&nbsp;#    strings "$2" | grep "$1" | tr -s "$IFS" '[\n*]'  34&nbsp;  35&nbsp;  36&nbsp;#  Try something like  "./bin-grep.sh mem /bin/ls"  37&nbsp;#+ to exercise this script.  38&nbsp;  39&nbsp;exit 0</PRE></TD></TR></TABLE><HR></DIV><P>More of the same.</P><DIVCLASS="EXAMPLE"><HR><ANAME="USERLIST"></A><P><B>Example 10-8. Listing all users on the system</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><PRECLASS="PROGRAMLISTING">   1&nbsp;#!/bin/bash   2&nbsp;# userlist.sh   3&nbsp;   4&nbsp;PASSWORD_FILE=/etc/passwd   5&nbsp;n=1           # User number   6&nbsp;   7&nbsp;for name in $(awk 'BEGIN{FS=":"}{print $1}' &#60; "$PASSWORD_FILE" )   8&nbsp;# Field separator = :    ^^^^^^   9&nbsp;# Print first field              ^^^^^^^^  10&nbsp;# Get input from password file               ^^^^^^^^^^^^^^^^^  11&nbsp;do  12&nbsp;  echo "USER #$n = $name"  13&nbsp;  let "n += 1"  14&nbsp;done    15&nbsp;  16&nbsp;  17&nbsp;# USER #1 = root  18&nbsp;# USER #2 = bin  19&nbsp;# USER #3 = daemon  20&nbsp;# ...  21&nbsp;# USER #30 = bozo  22&nbsp;  23&nbsp;exit 0  24&nbsp;  25&nbsp;#  Exercise:  26&nbsp;#  --------  27&nbsp;#  How is it that an ordinary user (or a script run by same)  28&nbsp;#+ can read /etc/passwd?  29&nbsp;#  Isn't this a security hole? Why or why not?</PRE></TD></TR></TABLE><HR></DIV><P>A final example of the <TTCLASS="USERINPUT"><B>[list]</B></TT>	      resulting from command substitution.</P><DIVCLASS="EXAMPLE"><HR><ANAME="FINDSTRING"></A><P><B>Example 10-9. Checking all the binaries in a directory for	      authorship</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><PRECLASS="PROGRAMLISTING">   1&nbsp;#!/bin/bash   2&nbsp;# findstring.sh:   3&nbsp;# Find a particular string in the binaries in a specified directory.   4&nbsp;   5&nbsp;directory=/usr/bin/   6&nbsp;fstring="Free Software Foundation"  # See which files come from the FSF.   7&nbsp;   8&nbsp;for file in $( find $directory -type f -name '*' | sort )   9&nbsp;do  10&nbsp;  strings -f $file | grep "$fstring" | sed -e "s%$directory%%"  11&nbsp;  #  In the "sed" expression,  12&nbsp;  #+ it is necessary to substitute for the normal "/" delimiter  13&nbsp;  #+ because "/" happens to be one of the characters filtered out.  14&nbsp;  #  Failure to do so gives an error message (try it).  15&nbsp;done    16&nbsp;  17&nbsp;exit 0  18&nbsp;  19&nbsp;#  Exercise (easy):  20&nbsp;#  ---------------  21&nbsp;#  Convert this script to take command-line parameters  22&nbsp;#+ for $directory and $fstring.</PRE></TD></TR></TABLE><HR></DIV><P><ANAME="LOOPREDIR"></A></P><P>The output of a <ICLASS="FIRSTTERM">for loop</I> may	      be piped to a command or commands.</P><DIVCLASS="EXAMPLE"><HR><ANAME="SYMLINKS"></A><P><B>Example 10-10. Listing the <ICLASS="FIRSTTERM">symbolic	        links</I> in a directory</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><PRECLASS="PROGRAMLISTING">   1&nbsp;#!/bin/bash   2&nbsp;# symlinks.sh: Lists symbolic links in a directory.   3&nbsp;   4&nbsp;   5&nbsp;directory=${1-`pwd`}   6&nbsp;#  Defaults to current working directory,   7&nbsp;#+ if not otherwise specified.   8&nbsp;#  Equivalent to code block below.   9&nbsp;# ----------------------------------------------------------  10&nbsp;# ARGS=1                 # Expect one command-line argument.  11&nbsp;#  12&nbsp;# if [ $# -ne "$ARGS" ]  # If not 1 arg...  13&nbsp;# then  14&nbsp;#   directory=`pwd`      # current working directory  15&nbsp;# else  16&nbsp;#   directory=$1  17&nbsp;# fi  18&nbsp;# ----------------------------------------------------------  19&nbsp;  20&nbsp;echo "symbolic links in directory \"$directory\""  21&nbsp;  22&nbsp;for file in "$( find $directory -type l )"   # -type l = symbolic links  23&nbsp;do  24&nbsp;  echo "$file"  25&nbsp;done | sort                                  # Otherwise file list is unsorted.  26&nbsp;#  Strictly speaking, a loop isn't really necessary here,  27&nbsp;#+ since the output of the "find" command is expanded into a single word.  28&nbsp;#  However, it's easy to understand and illustrative this way.  29&nbsp;  30&nbsp;#  As Dominik 'Aeneas' Schnitzer points out,  31&nbsp;#+ failing to quote  $( find $directory -type l )  32&nbsp;#+ will choke on filenames with embedded whitespace.  33&nbsp;#  Even this will only pick up the first field of each argument.  34&nbsp;  35&nbsp;exit 0  36&nbsp;  37&nbsp;  38&nbsp;# --------------------------------------------------------  39&nbsp;# Jean Helou proposes the following alternative:  40&nbsp;  41&nbsp;echo "symbolic links in directory \"$directory\""  42&nbsp;# Backup of the current IFS. One can never be too cautious.  43&nbsp;OLDIFS=$IFS  44&nbsp;IFS=:  45&nbsp;  46&nbsp;for file in $(find $directory -type l -printf "%p$IFS")  47&nbsp;do     #                              ^^^^^^^^^^^^^^^^  48&nbsp;       echo "$file"  49&nbsp;       done|sort  50&nbsp;  51&nbsp;# And, James "Mike" Conley suggests modifying Helou's code thusly:  52&nbsp;  53&nbsp;OLDIFS=$IFS  54&nbsp;IFS='' # Null IFS means no word breaks  55&nbsp;for file in $( find $directory -type l )  56&nbsp;do  57&nbsp;  echo $file  58&nbsp;  done | sort  59&nbsp;  60&nbsp;#  This works in the "pathological" case of a directory name having  61&nbsp;#+ an embedded colon.  62&nbsp;#  "This also fixes the pathological case of the directory name having  63&nbsp;#+  a colon (or space in earlier example) as well."  64&nbsp;</PRE></TD></TR></TABLE><HR></DIV><P>The <TTCLASS="FILENAME">stdout</TT> of a loop may be <AHREF="io-redirection.html#IOREDIRREF">redirected</A> to a file, as this slight	      modification to the previous example shows.</P><DIVCLASS="EXAMPLE"><HR><ANAME="SYMLINKS2"></A><P><B>Example 10-11. Symbolic links in a directory, saved to a file</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><PRECLASS="PROGRAMLISTING">   1&nbsp;#!/bin/bash   2&nbsp;# symlinks.sh: Lists symbolic links in a directory.   3&nbsp;   4&nbsp;OUTFILE=symlinks.list                         # save file   5&nbsp;   6&nbsp;directory=${1-`pwd`}   7&nbsp;#  Defaults to current working directory,   8&nbsp;#+ if not otherwise specified.   9&nbsp;  10&nbsp;  11&nbsp;echo "symbolic links in directory \"$directory\"" &#62; "$OUTFILE"  12&nbsp;echo "---------------------------" &#62;&#62; "$OUTFILE"  13&nbsp;  14&nbsp;for file in "$( find $directory -type l )"    # -type l = symbolic links  15&nbsp;do  16&nbsp;  echo "$file"  17&nbsp;done | sort &#62;&#62; "$OUTFILE"                     # stdout of loop  18&nbsp;#           ^^^^^^^^^^^^^                       redirected to save file.  19&nbsp;  20&nbsp;exit 0</PRE></TD></TR></TABLE><HR></DIV><P><ANAME="LOOPCSTYLE"></A></P><P>There is an alternative syntax to a <ICLASS="FIRSTTERM">for	      loop</I> that will look very familiar to C	      programmers. This requires <AHREF="dblparens.html#DBLPARENSREF">double parentheses</A>.</P><DIVCLASS="EXAMPLE"><HR><ANAME="FORLOOPC"></A><P><B>Example 10-12. A C-style <ICLASS="FIRSTTERM">for</I> loop</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><PRECLASS="PROGRAMLISTING">   1&nbsp;#!/bin/bash   2&nbsp;# Two ways to count up to 10.   3&nbsp;   4&nbsp;echo   5&nbsp;   6&nbsp;# Standard syntax.   7&nbsp;for a in 1 2 3 4 5 6 7 8 9 10   8&nbsp;do   9&nbsp;  echo -n "$a "  10&nbsp;done    11&nbsp;  12&nbsp;echo; echo  13&nbsp;  14&nbsp;# +==========================================+  15&nbsp;  16&nbsp;# Now, let's do the same, using C-like syntax.  17&nbsp;  18&nbsp;LIMIT=10  19&nbsp;  20&nbsp;for ((a=1; a &#60;= LIMIT ; a++))  # Double parentheses, and "LIMIT" with no "$".  21&nbsp;do  22&nbsp;  echo -n "$a "  23&nbsp;done                           # A construct borrowed from 'ksh93'.  24&nbsp;  25&nbsp;echo; echo  26&nbsp;  27&nbsp;# +=========================================================================+  28&nbsp;  29&nbsp;# Let's use the C "comma operator" to increment two variables simultaneously.  30&nbsp;  31&nbsp;for ((a=1, b=1; a &#60;= LIMIT ; a++, b++))  # The comma chains together operations.  32&nbsp;do  33&nbsp;  echo -n "$a-$b "  34&nbsp;done  35&nbsp;  36&nbsp;echo; echo  37&nbsp;  38&nbsp;exit 0</PRE></TD></TR></TABLE><HR></DIV><P>See also <AHREF="arrays.html#QFUNCTION">Example 26-16</A>, <AHREF="arrays.html#TWODIM">Example 26-17</A>, and <AHREF="contributed-scripts.html#COLLATZ">Example A-6</A>.</P><P>---</P><P>Now, a <ICLASS="FIRSTTERM">for loop</I> used in a	      <SPANCLASS="QUOTE">"real-life"</SPAN> context.</P><DIVCLASS="EXAMPLE"><HR><ANAME="EX24"></A><P><B>Example 10-13. Using <ICLASS="FIRSTTERM">efax</I> in batch mode</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><PRECLASS="PROGRAMLISTING">   1&nbsp;#!/bin/bash   2&nbsp;# Faxing (must have 'efax' package installed).   3&nbsp;   4&nbsp;EXPECTED_ARGS=2   5&nbsp;E_BADARGS=65   6&nbsp;MODEM_PORT="/dev/ttyS2"   # May be different on your machine.   7&nbsp;#                ^^^^^      PCMCIA modem card default port.   8&nbsp;   9&nbsp;if [ $# -ne $EXPECTED_ARGS ]  10&nbsp;# Check for proper number of command line args.  11&nbsp;then  12&nbsp;   echo "Usage: `basename $0` phone# text-file"  13&nbsp;   exit $E_BADARGS  14&nbsp;fi  15&nbsp;  16&nbsp;  17&nbsp;if [ ! -f "$2" ]  18&nbsp;then  19&nbsp;  echo "File $2 is not a text file."  20&nbsp;  #     File is not a regular file, or does not exist.  21&nbsp;  exit $E_BADARGS  22&nbsp;fi  23&nbsp;    24&nbsp;  25&nbsp;fax make $2              #  Create fax-formatted files from text files.  26&nbsp;  27&nbsp;for file in $(ls $2.0*)  #  Concatenate the converted files.  28&nbsp;                         #  Uses wild card (filename "globbing")  29&nbsp;			 #+ in variable list.  30&nbsp;do  31&nbsp;  fil="$fil $file"  32&nbsp;done    33&nbsp;  34&nbsp;efax -d "$MODEM_PORT"  -t "T$1" $fil   # Finally, do the work.  35&nbsp;# Trying adding  -o1  if above line fails.  36&nbsp;  37&nbsp;  38&nbsp;#  As S.C. points out, the for-loop can be eliminated with  39&nbsp;#     efax -d /dev/ttyS2 -o1 -t "T$1" $2.0*  40&nbsp;#+ but it's not quite as instructive [grin].  41&nbsp;  42&nbsp;exit $?   # Also, efax sends diagnostic messages to stdout.</PRE></TD></TR></TABLE><HR></DIV></DD><DT><ANAME="WHILELOOPREF"></A><BCLASS="COMMAND">while</B></DT><DD><P>This construct tests for a condition at the top of a	      loop, and keeps looping as long as that condition	      is true (returns a <SPANCLASS="RETURNVALUE">0</SPAN> <AHREF="exit-status.html#EXITSTATUSREF">exit status</A>).  In contrast	      to a <AHREF="loops.html#FORLOOPREF1">for loop</A>, a	      <ICLASS="FIRSTTERM">while loop</I> finds use in situations	      where the number of loop repetitions is not known	      beforehand.</P><P><P><BCLASS="COMMAND">while</B>  [<TTCLASS="REPLACEABLE"><I> condition </I></TT>]<BR>  do <BR>  <TTCLASS="REPLACEABLE"><I>燾ommand(s)</I></TT>... <BR>  done </P></P><P>The bracket construct in a <ICLASS="FIRSTTERM">while	      loop</I> is nothing more than our old friend,	      the <AHREF="tests.html#TESTCONSTRUCTS1">test brackets</A>	      used in an <ICLASS="FIRSTTERM">if/then</I> test. In fact,	      a <ICLASS="FIRSTTERM">while loop</I> can legally use the	      more versatile <AHREF="tests.html#DBLBRACKETS">double brackets	      construct</A> (while [[ condition ]]).</P><P><ANAME="WHILENEEDSEMI"></A></P><P><AHREF="loops.html#NEEDSEMICOLON">As is the case with	      <ICLASS="FIRSTTERM">for loops</I></A>, placing the	      <ICLASS="FIRSTTERM">do</I> on the same line as the condition	      test requires a semicolon.</P><P><P><BCLASS="COMMAND">while</B>  [<TTCLASS="REPLACEABLE"><I> condition </I></TT>]  ;   do </P></P><P>Note that the <ICLASS="FIRSTTERM">test brackets</I

⌨️ 快捷键说明

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