Learning_the_bash_Shell_Third_Edition 11/n

for|case|select|while and until

 

Command-Line Options and Typed Variables

Command-Line Options

 

Typical UNIX commands have the form command [-options]args, meaning that there can be 0 or more options. If a shell script processes the command teatime alice hatter, then $1 is “alice” and $2 is “hatter”. But if the command is teatime -o alice hatter, then $1 is -o, $2 is “alice”, and $3 is “hatter”.

 You might think you could write code like this to handle it:

if [ $1 = -o ]; then
code that processes the -o option
1=$2
2=$3
fi
normal processing of $1 and $2...

  

But this code has several problems. First, assignments like 1=$2 are illegal because positional parameters are read-only. Even if they were legal, another problem is that this kind of code imposes limitations on how many arguments the script can handle—which is very unwise. Furthermore, if this command had several possible options, the code to handle all of them would get very messy very quickly.

 shift

The getopts built-in command, which we will introduce later, provides this help.

 

if [ -n "$(echo $1 | grep '^-[0-9][0-9]*$')" ]; then
howmany=$1
shift
elif [ -n "$(echo $1 | grep '^-')" ]; then
print 'usage: highest [-N] filename'
exit 1
else
howmany="-10"
fi
filename=$1
sort -nr $filename | head $howmany

  

This uses the grep search utility to test if $1 matches the appropriate pattern. To do this we provide the regular expression ^-[0-9][0-9]*$ to grep, which is interpreted as “an initial dash followed by a digit, optionally followed by one or more digits.” If a match is found then grep will return the match and the test will be true, otherwise grep will return nothing and processing will pass to the elif test. Notice that we have enclosed the regular expression in single quotes to stop the shell from interpreting the $ and *, and pass them through to grep unmodified.

 

For the sake of concreteness, assume that our script is called alice and we want to handle the options -a, -b, and -c:

 

while [ -n "$(echo $1 | grep '-')" ]; do
  case $1 in
    -a ) process option -a ;;
    -b ) process option -b ;;
    -c ) process option -c ;;
    * ) echo 'usage: alice [-a] [-b] [-c] args...'
      exit 1
  esac
  shift
done normal processing of arguments...

  

#shift在干什么?let's see

cor@debian:~/shell/mar5$ cat 2.sh 
echo "=================="
echo ${#*}  #查看当前position 参数的个数
echo 'position 1 = '${1:-None}  #如果有就返回,否则返回None
echo 'position 2 = '${2:-None}
echo 'position 3 = '${3:-None}
echo "========1========"
shift
echo ${#*}
echo 'position 1 = '${1:-None}
echo 'position 2 = '${2:-None}
echo 'position 3 = '${3:-None}
shift
echo "========2========"
echo 'position 1 = '${1:-None}
echo 'position 2 = '${2:-None}
echo 'position 3 = '${3:-None}
shift
echo ${#*}
echo "========3========"
echo 'position 1 = '${1:-None}
echo 'position 2 = '${2:-None}
echo 'position 3 = '${3:-None}

  result:

cor@debian:~/shell/mar5$ . 2.sh a b c 
==================
3 #第一次的总数是3
position 1 = a
position 2 = b
position 3 = c
========1========
2 # shift 后原来的 $1 被remove 掉了,后面的往前顶
position 1 = b
position 2 = c
position 3 = None #此时,position 3 的返回值是None
========2========
position 1 = c
position 2 = None
position 3 = None
0
========3========
position 1 = None
position 2 = None
position 3 = None

  

Options with Arguments

Assume that, in our alice script, the option -b requires its own argument. Here is the modified code that will process it:

 

while [ -n "$(echo $1 | grep '-')" ]; do
case $1 in
-a ) process option -a ;;
-b ) process option -b
$2 is the option's argument
shift ;;
-c ) process option -c ;;
* ) echo 'usage: alice [-a] [-b barg] [-c] args...'
exit 1
esac
shift
done
normal processing of arguments...

  

getopts

So far, we have a complete, but constrained, way of handling command-line options.The above code does not allow a user to combine arguments with a single dash, e.g., -abc instead of -a -b -c. It also doesn’t allow one to specify arguments to options without a space in between, e.g., -barg in addition to -b arg.

 

getopts takes two arguments. The first is a string that can contain letters and colons.Each letter is a valid option; if a letter is followed by a colon, the option requires an argument. getopts picks options off the command line and assigns each one (without the leading dash) to a variable whose name is getopts’s second argument. As long as there are options left to process, getopts will return exit status 0; when the options are exhausted, it returns exit status 1, causing the while loop to exit.

 

while getopts ":ab:c" opt; do
  case $opt in
    a ) process option -a ;;
    b ) process option -b
        $OPTARG is the option's argument ;;
    c ) process option -c ;;
    \? ) echo 'usage: alice [-a] [-b barg] [-c] args...'
    exit 1
  esac
done
shift $(($OPTIND - 1))
normal processing of arguments...

  

 

posted @ 2021-03-04 16:29  碧水东流至此回  阅读(51)  评论(1编辑  收藏  举报