• Shell编程—用户输入


    1命令行参数

    1.1读取参数

    bash shell会将一些称为位置参数(positional parameter)的特殊变量分配给输入到命令行中的所有参数。这也包括shell所执行的脚本名称。位置参数变量是标准的数字:$0是程序名,$1是第一个参数,$2是第二个参数,依次类推,直到第九个参数$9。

    例子:计算阶乘

    $ vim test1.sh
    #!/bin/bash
    # using one command line parameter
    factorial=1
    for (( number = 1; number <= $1 ; number++ )) 
    do 
       factorial=$[ $factorial * $number ] 
    done 
    echo The factorial of $1 is $factorial
    
    $ ./test1.sh 5
    The factorial of 5 is 120

    1.2读取脚本名

    以用$0参数获取shell在命令行启动的脚本名。

    $ cat test5.sh 
    #!/bin/bash 
    # Testing the $0 parameter 
    echo The zero parameter is set to: $0 
     
    $bash test5.sh
    The zero parameter is set to: test5.sh

    但是这里存在一个潜在的问题。如果使用另一个命令来运行shell脚本,命令会和脚本名混在一起,出现在$0参数中。比如:

    $ ./test5.sh
    The zero parameter is set to: ./test5.sh
    $ bash /home/Christine/test5.sh
    The zero parameter is set to: /home/Christine/test5.sh

    这个时候basename命令可以帮助我们,basename命令会返回不包含路径的脚本名。

    $ cat test5b.sh
    #!/bin/bash
    # Using basename with the $0 parameter
    name=$(basename $0) 
    echo echo The script name is: $name
    
    
    $ bash /home/Christine/test5b.sh
    The script name is: test5b.sh
    
    $ ./test5b.sh
    The script name is: test5b.sh

    可以用这种方法来编写基于脚本名执行不同功能的脚本。这里有个简单的例子:

    $ cat test6.sh 
    #!/bin/bash 
    name=$(basename $0) 
    #判断参数是否为空,如果为空的话(就是执行脚本时少带了参数),后面的脚本会报错
    if [ -e  $1 ]
    then
    echo "$1 is empty"
    exit 1
    elif [ -e $2 ]
    then
    echo "$2 is empty"
    exit 1
    fi
    
    if [ $name = "addem" ] 
    then 
       total=$[ $1 + $2 ] 
    elif [ $name = "multem" ] 
    then 
       total=$[ $1 * $2 ] 
    fi 
    echo The calculated value is $total 
    
    开始测试:
    $ cp test6.sh addem 
    $ chmod u+x addem 
    $ ln -s test6.sh multem 
    $ ls -l *em 
    -rwxrw-r--. 1 Christine Christine 224 Jun 30 23:50 addem 
    lrwxrwxrwx. 1 Christine Christine   8 Jun 30 23:50 multem -> test6.sh 
    
    $ ./addem 2 5 
    The calculated value is 7 
    
    $ ./multem 2 5 
    The calculated value is 10 

    本例从test6.sh脚本中创建了两个不同的文件名:一个通过复制文件创建(addem),另一个通过链接创建(multem)。在两种情况下都会先获得脚本的基本名称,然后根据该值执行相应的功能。

     

    2特殊参数变量

    2.1参数统计

    特殊变量$#:含有脚本运行时携带的命令行参数的个数

    $ cat test8.sh
    #!/bin/bash
    # getting the number of parameters
     echo There were $# parameters supplied.
    
    $ ./test8.sh
    There were 0 parameters supplied.
    
    $ ./test8.sh 1 2 3 4 5
    There were 5 parameters supplied.
    
    $ ./test8.sh 1 2 3 4 5 6 7 8 9 10 
    There were 10 parameters supplied.
     
    $ ./test8.sh "Rich Blum"
    There were 1 parameters supplied.

    如果要直接获取最后一个参数的值时,不应该用${$#},而是应该用${!#}:

    2.2抓取所有的数据

    $*和$@变量可以用来轻松访问所有的参数。这两个变量都能够在单个变量中存储所有的命令行参数。

    $*变量会将命令行上提供的所有参数当作一个单词保存,这个单词包含了命令行中出现的每一个参数值;

    $@变量会将命令行上提供的所有参数当作同一字符串中的多个独立的单词。

    例子:

    $ cat test10.sh
    #!/bin/bash
    # Grabbing the last parameter
    params=$# 
    echo echo The last parameter is $params 
    echo The last parameter is ${!#} 
    
    $ bash test10.sh 1 2 3 4 5  
    The last parameter is 5
    The last parameter is 5
     
    $ bash test10.sh
    The last parameter is 0
    The last parameter is test10.sh

     

    3移动变量

    shift命令能够用来操作命令行参数。它会根据相对位置来移动命令行参数。在使用shift命令时,默认情况下它会将每个参数变量向左移动一个位置。所以,变量$3的值会移到$2中,变量$2的值会移到$1中,而变量$1的值则会被删除(注意,变量$0的值,也就是程序名,不会改变)。

    $ cat test13.sh
    #!/bin/bash
    count=1 
    while [ -n "$1" ] 
    do 
       echo "Parameter #$count = $1"    
       count=$[ $count + 1 ]    
       shift 
    done
    
    $ ./test13.sh rich barbara katie jessica
    Parameter #1 = rich
    Parameter #2 = barbara 
    Parameter #3 = katie
    Parameter #4 = jessica

    另外,你也可以一次性移动多个位置,只需要给shift命令提供一个参数,指明要移动的位置数就行了。

    $ cat test14.sh
    #!/bin/bash
    echo "The original parameters: $*" 
    shift 2 
    echo "Here's the new first parameter: $1"
    
    $ ./test14.sh 1 2 3 4 5
    The original parameters: 1 2 3 4 5 
    Here's the new first parameter: 3

     

    4处理选项

    1. 处理简单选项

    $ cat test15.sh
    #!/bin/bash                                              
    # extracting command line options as parameters
    while [ -n "$1" ]      
    do  
      case "$1" in
    -a)  echo "Found the -a option" ;;
    -b)  echo "Found the -b option" ;; 
    -c)  echo "Found the -c option" ;;       
    *) echo "$1 is not an option" ;;    
     esac
    shift                                                      
    done
    
      $ ./test15.sh -a -b -c -d
    Found the -a option
    Found the -b option
    Found the -c option
    -d is not an option  

        

    2. 分离参数和选项

    双破折线(--):表明选项列表结束。

    $ cat test16.sh
    #!/bin/bash
    while [ -n "$1" ] 
    do  
      case "$1" in
    -a)  echo "Found the -a option" ;;
    -b)  echo "Found the -b option";;       
    -c) echo "Found the -c option" ;;
     --) shift           
        break ;;
    *) echo "$1 is not an option";;    
      esac    
      shift 
    done  
    count=1 
    for param in $@ 
    do  
      echo "Parameter #$count: $param"    
      count=$[ $count + 1 ] 
    done
    
    $ ./test16.sh -c -a -b test1 test2 test3
    Found the -c option
    Found the -a option 
    Found the -b option 
    test1 is not an option 
    test2 is not an option 
    test3 is not an option
    
    $ ./test16.sh -c -a -b -- test1 test2 test3
    Found the -c option
    Found the -a option
    Found the -b option
    Parameter #1: test1
    Parameter #2: test2 
    Parameter #3: test3

    3. 处理带值的选项

    $ cat test17.sh
    #!/bin/bash
    while [ -n "$1" ] 
    do  
      case "$1" in
    -a)  echo "Found the -a option";;
    -b)  param="$2"           
         echo "Found the -b option, with parameter value $param"           
         shift ;;
    -c)  echo "Found the -c option";;
    --) shift          
         break ;;
    *) echo "$1 is not an option";;   
     esac    
     shift 
     done 
     count=1 
     for param in "$@" 
     do 
        echo "Parameter #$count: $param"    
        count=$[ $count + 1 ] 
     done
    
    $ ./test17.sh -a -b test1 -d 
    Found the -a option
    Found the -b option, with parameter value test1
    -d is not an option

    但是这种脚本遇到$ ./test17.sh -ac的命令九九没法执行了。

     

    5将选项标准化

    选  项

    描  述

    -a

    显示所有对象

    -c

    生成一个计数

    -d

    指定一个目录

    -e

    扩展一个对象

    -f

    指定读入数据的文件

    -h

    显示命令的帮助信息

    -i

    忽略文本大小写

    -l

    产生输出的长格式版本

    -n

    使用非交互模式(批处理)

    -o

    将所有输出重定向到的指定的输出文件

    -q

    以安静模式运行

    -r

    递归地处理目录和文件

    -s

    以安静模式运行

    -v

    生成详细输出

    -x

    排除某个对象

    -y

    对所有问题回答yes

     

    6获得用户输入

    6.1基本的读取

    read命令从标准输入(键盘)或另一个文件描述符中接受输入。在收到输入后,read命令会将数据放进一个变量

    $ cat test22.sh
    #!/bin/bash
    # testing the read -p option
    read -p "Please enter your age: " age 
    days=$[ $age * 365 ] 
    echo "That makes you over $days days old! "
    
    $ ./test22.sh
    Please enter your age: 10
    That makes you over 3650 days old!

     6.2 超时

    使用read命令时要当心。脚本很可能会一直苦等着脚本用户的输入。如果不管是否有数据输入,脚本都必须继续执行,你可以用-t选项来指定一个计时器。-t选项指定了read命令等待输入的秒数。当计时器过期后,read命令会返回一个非零退出状态码。

    $ cat test25.sh 
    #!/bin/bash 
    # timing the data entry 
    if read -t 5 -p "Please enter your name: " name 
    then
        echo "Hello $name, welcome to my script" 
    else
        echo 
        echo "Sorry, too slow! " 
    fi 
        
    $ ./test25.sh
    Please enter your name: Rich
    Hello Rich, welcome to my script 
    
    $ ./test25.sh
    Please enter your name:
    Sorry, too slow!

    如果计时器过期,read命令会以非零退出状态码退出,可以使用如if-then语句或while循环这种标准的结构化语句来理清所发生的具体情况。

     

    也可以不对输入过程计时,而是让read命令来统计输入的字符数。当输入的字符达到预设的字符数时,就自动退出,将输入的数据赋给变量。

    $ cat test26.sh
    #!/bin/bash
    # getting just one character of input
    read -n1 -p "Do you want to continue [Y/N]? " answer 
    case $answer in 
    Y | y) echo "fine, continue on…";; 
    N | n) echo "OK, goodbye"        
           exit;; 
    esac 
    echo "This is the end of the script"
    
    $ ./test26.sh
    Do you want to continue [Y/N]? Y 
    fine, continue on…
    This is the end of the script
    
    $ ./test26.sh
    Do you want to continue [Y/N]? n
    OK, goodbye

    本例中将-n选项和值1一起使用,告诉read命令在接受单个字符后退出。只要按下单个字符回答后,read命令就会接受输入并将它传给变量,无需按回车键。

  • 相关阅读:
    雷军复盘小米下滑原因:线上遭恶性竞争 线下错过县乡市场(小米是手机公司,也是移动互联网公司,更是新零售公司)
    Web前端开发人员实用Chrome插件收集
    批量删除C和C++注释
    一个Windows C++的线程类实现(封装API,形成一个类,但不完善。其实可以学习一下Delphi的TThread的写法)
    协程在Web服务器中的应用(配的图还不错)
    MVC OR API的接口
    Core MVC
    WCF SOAP
    标签辅助类
    构建微服务:Spring boot
  • 原文地址:https://www.cnblogs.com/ericz2j/p/12045596.html
Copyright © 2020-2023  润新知