处理用户输入(代码片段)

burnovblog burnovblog     2022-12-02     136

关键词:

  脚本程序需要能与运行脚本程序的人员进行交互,bash shell提供了一些不同的方法来从用户处获取数据,这些方法包括命令行参数、命令行选项和直接读取键盘输入;

1、命令行参数

  向shell脚本传递数据的基本方式是使用命令行参数(command line parameters)。使用命令行参数可以在执行脚本时向命令行中添加数据值

./addem 10 30  #向addem脚本传入 10 30 两个参数

  1.1、读取参数

    bash shell将在命令行中输入所有参数复制给一些特殊变量,这些变量称之为位置参数(positional parameter)。

    $0为程序名称

    $1为第一个参数

    $2为第二个参数

    依次类推;

#!/bin/bash
# using one command line paramter

factorial=1
for (( number = 1; number <= $1; number++ ))
do
    factorial=$[ $factorial * $number ]
done
echo The factorial of $1 is $factorial
./test1 5

    如果需要输入更多的命令行参数,那么必须在命令行中使用空格分隔每个参数;

#!/bin/bash
# testing two command line parameters

total=$[ $1 * $2 ]
echo The first parameter is $1.
echo The second parameter is $2.
echo The total value is $total.
./test2 2 5

    输入参数,除了数值外,依然可以输入文本字符串

#!/bin/bash
# testing string parameters

echo Hello $1,glad to meet you.
./test3 Rich

    如果输入的参数包含空格,则必须用引号引起来;

    如果脚本输入的参数多余9个,第十个参数就要将10用花括号括起来--$10

#!/bin/bash
# handling lots of parameters

total=$[ $10 * $11 ]
echo The tenth parameter is $10
echo The eleventh parameter is $11
echo The total is $total
./test4 1 2 3 4 5 6 7 8 9 10 11 12

  1.2、读取程序名称

    通过$0来提取shell脚本的名称

#!/bin/bash
# testing the $0 parameter

echo The command entered is: $0

    传递给$0的是完整的路径,而不是相对路径;

    但是我们希望只是获取脚本名称,不要路径;这时候我们通过basename命令可以;

#!/bin/bash
# using basename with the $0 parameter

name=`basename $0`
echo The command entered is: $name

    这时候只会留下脚本名字;

    这样的话,就可以利用这个名称来编写一些特定功能脚本;

#!/bin/bash
# testing a multi-function script

name=`basename $0`
if [ $name = "addem" ]
then
    total=$[ $1 + $2 ]
elif [ $name = "mutlem" ]
then
    total=$[ $1 * $2 ]
fi
echo The calculated value is $total
chmod u+x test6
cp test6 addem
ln -s test6 multem
ls -l
./addem 2 5
./multem 2 5

  1.3、测试参数

    如果缺少参数,则会报错:会提示语法错误

./addme: line 8: 2 + : syntax error: operand expected (error token is " ")

    当脚本变量认为里面有数据时,但是实际上没有参数,这样就会出现很多不好的情况。

#!/bin/bash
# testing parameters before use

if [ -n "$1" ]
then
    echo Hello $1,glad to meet you.
else
    echo "Sorry,you didn‘t identify yourself."
fi
./test7 Rich
./test7 Rich
Sorry, you didn‘t identify youself.  #这样的提示就会好一些

2、特殊的参数变量

  在bash shell脚本中有一些特殊的参数

  2.1、参数计数

    $?  可以统计输入参数变量的数量;

#!/bin/bash
# getting the number of parameters

echo There were $# parameters supplied
./test8
./test8 1 2 3 4 5
./test8 "Rich Blum"

    现在可以在使用参数前测试现有的参数个数:

#!/bin/bash
# testing parameters

if [ $# -ne 2 ]
then
  echo Usage: test9 a b
else
  total=$[ $1 + $2 ]
  echo The total is $total
fi
./test9
./test9 10
./test9 10 15
./test9 10 15 20

    $$#  #不能表示最后一个参数,这是一种错误的写法

#!/bin/bash
# testing grabbing last parameter

echo The last parameter war $$#
./badtest1 10  #理论上返回的是10,但实际上不是

    如果想得到想要的结果,这里表明,不能在大括号中添加$符号,必须将$符号替换为!才行;

#!/bin/bash
# Grabbing the last parameter

params=$#
echo The last parameter is $params
echo The last parameter is $!#
./test10 1 2 3 4 5
The last parameter is 5
The last parameter is 5
./test10
The last parameter is 0
The last parameter is ./test10

  2.2、获取所有数据

    有时候,需要获取命令中所有参数,对这些参数进行循环。

    $*和[email protected]为所有参数提供了“一站式购物”服务,这两个变量都是在一个变量中包含所有的命令行参数。

    $* 将多个变量视为一个单词处理。

    [email protected]将命令中提供的参数视为一个字符串中的多个单词处理;

#!/bin/bash
# testing $* and [email protected]

echo "Using the \\$* method: $*"
echo "Using the \\[email protected] method: [email protected]"
./test1 rich barbara katie jessica
Using the $* method: rich barbara katie jessica
Using the [email protected] method: rich barbara katie jessica

    再看一个例子

#!/bin/bash
# testing $* and [email protected]

count=1
for param in "$*"
do
    echo "\\$* Parameter #$count = $param"
    count=$[ $count + 1 ]
done

count=1
for param in "#@"
do
    echo "\\[email protected] Parameter #$count = $param"
    count=$[ $count + 1 ]
done
./test12 rich barbara katie jessica

    在使用for命令迭代特殊变量的时候,使用$*只进行一次。而[email protected]则是将所有的变量都遍历一遍;

3、位移

  shift命令。bash shell提供了shift命令来对传参进行推进,改变命令行参数的位置。

  没执行一次命令,则参数变量可以左移以为。于是$3就会变为$2。

#!/bin/bash
# demonstrating the shift command

count=1
while [ -n "$1" ]
do
    echo "Parameter #$count = $1"
    count=$[ $count + 1 ]
    shift
done
./test13 rich barbara katie jessica

  脚本执行while循环,测试第一个参数的数值长度,当长度为0的时候,结束循环。

#!/bin/bash
# demonstrating a multi-postion shift

echo "The original parameters: $*"
shift 2
echo "Here‘s the new first parameter: $1"
./test14 1 2 3 4 5

  此时$1应该代表的是 3 ,因为之前执行了 shift 2 将参数向前移动了两位

4、处理选项 

  选型就是脚本作为执行命令的时候,需要指定的特殊功能;这里我们需要自己来定义;

  4.1、找出选项

    1、处理简单的选项

    抽取每个参数时,使用case语句判断参数是否符合选项格式:

#!/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

    case语句检查每个参数是否有效的选项。当找到一个选项时,就在case语句中运行适当的命令,以后,这些功能我们会以函数的形式写在下面,供这里来调用;

    2、从参数中分离选项

    命令中分离参数与选项

#!/bin/bash
# extracting options and 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";;
    --) shift  #保证 -- 从参数变量中丢弃
        break ;;
    *) echo "$1 is not an option";;
    esac
    shift
done

count=1
for param in [email protected]
do
    echo "Parameter #$count: $param"
    count=$[ $count + 1 ]
done
./test16 -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 -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、处理带值的选项

    有限选项需要附加参数值。这种情况下,命令形式与下面的格式类似;

./testing -a test1

    例子:

#!/bin/bash
# extracting command line options and values

while [ -n "$1" ]
do 
    case "$1" in
    -a) echo "Found the -a option";;
    -b) param="$2"  #这个有一个附加参数值,位于$2
         echo "Found the -b option,with parameter value $param"
         shift 2;;
    -c) ehco "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 -b test1 -a -d

    但是如果要将短选项合并呢, ./test17 -ac  则又会报错;

  4.2、使用getopt命令

    getopt用来处理命令行与选项之间的关系非常不错;

    1、命令模式

    getopt用法:getopt options optstring parameters

    选项字符optsting是处理的关键。它定义了命令行中的有限选项字母。还定义了这些选项字母的相关参数;

getopt ab:cd -a -b test1 -cd test2 test3

    如果使用命令不在getopt定义的选项字符串中,这样就会报错

getopt ab:cd -a -b test1 -cde test2 test3
getopt: invalid option -- e
-a -b test1 -c -d -- test2 test3

    如果先忽略这个错误 -q 就可以了;

    2、在脚本中使用getopt

    我们需要将现有的命令行选项和参数替换为getopt命令生成的格式化形式。方法是通过set命令来实现;

#!/bin/bash
# extracting command line options and values with getopt

set -- `getopt -q ab:c "[email protected]"`
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 "[email protected]"
do
    echo "Parameter #$count: $param"
    count=$[ $count + 1 ] 
done
./test18 -ac
./test18 -a -b test1 -cd test2 test3 test4
./test18 -a -b test1 -cd "test2 test3" test  #这样分别将 "test2 和 test3" 视为两个值了

  4.3、更高级的getopts命令

    getopt为命令行中找到的素有待处理选项和参数生成一个输出,而与getopt不同,getopts命令顺序对现有shell参数变量进行处理;

    每调用一次getopts,它只处理在命令中检测到的参数中的一个。处理完所有参数后,以大于零的退出转态退出。因此,getopts非常适合用在循环中解析所有的命令行参数。

    getopts用法:getopts optstring variable

#!/bin/bash
# smiple demonstration of the getopts command

while getopts :ab:c opt
do 
    case "$opt" in
    a) echo "Found the -a option" ;;
    b) echo "Found the -b option, with value $OPTARG" ;;
    c) echo "Found the -c option" ;;
    *) echo "Unknow option: $opt" ;;
    esac
done
./test19 -ab test1 -c
./test19 -b "test1 test2" -a

    getopts命令可以将正确的选项以及参数解析处理啊。getopts名里还可以将命令中找到的为定义的选项都绑定为一个符号输出--问号

./test19 -d

    getopts每个处理选项,环境变量OPTIND的值会增加1.当达到getopts处理的末尾的时候,可以使用shift命令和OPTIND值进行操作来移动到参数:

#!/bin/bash
# processing options and parameters wiht getopts

while getopts :ab:cd opt
do
    case "$opt" in
    a) echo "Found the -a option" ;;
    b) echo "Found the -b option, with value $OPTARG" ;;
    c) echo "Found the -c option" ;;
    d) echo "Found the -d option" ;;
    *) echo "Unknown option: $opt" ;;
    esac
done
shift $[ $OPTIND - 1 ]

count=1
for param in "[email protected]"
do
    echo "Parameter $count: $param"
    count=$[ Parameter $count: $param]
done
./test20 -a -b test1 -d test2 test3 test4

    至此,就拥有了可以用于所有shell脚本的完整功能;

5、标准化选项

  在Linux的世界里面,那些字母具有那些特定的意义呢?

技术图片

6、获取用户输入

  参数是一种输入数据的方式,有时候要进入交互式的方式进行输入选择,这时候就需要通过read的方式来实现;

  6.1、基本读取

#!/bin/bash
# testing the read command

echo -n "Enter your name: "  #不换行
read name  #读取name的值
echo "Hello $name, welcome to my program."

    事实上不用这么麻烦,直接使用 -p 的参数就可以了

#!/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!"

    直接使用 read -p 参数就避免的了使用echo -n 在加 read 的这种组合

    事实上,read -p 后面同样可以添加多个变量值

#!/bin/bash
# entering multiple variables

read -p "Enter your name: " first last
echo "Checking data for $last, $first ..."

    这个例子中,first,last分别是read 后输入的两个变量值,在后面的代码中可以直接调用;

    read也可以不用指定变量,那么read所接受到的环境变量值就会被默认放在REPLY中;

#!/bin/bash
# testing the REPLY environment variable

read -p "Enter a number: "
factorial=1
for (( count=1; count <= $REPLY; count++ ))
do
    factorial=$[ $factorial * $count ]
done
echo "The factorial of $REPLY is $factorial"

  6.2、计时

    使用read存在着潜在的危险。会一直等待用户输入数据,这时候就可以使用 -t 参数指定在规定时间内输入数据,如果不输入就会执行下面的命令;

#!/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

    除了计时,还可以规定输入内容的字符数量

#!/bin/bash
# getting just one character of input

read -n1 -p "Do you want to contnue [Y/N]? " answer
case $answer in
Y | y) echo
         echo "fine, contnue on ... ";;
N | n) echo
         echo OK, goodbye
         exit;;
esac
echo "This is the end of the script"

  6.3、默读

    有时候,输入的内容不希望显示在显示器上,比如密码;

    这时候,我们使用-s的参数来实现;

#!/bin/bash
# hiding input data from the monitor

read -s -p "Enter your password: " pass
echo
echo "Is your password really $pass?"

  6.4、读取文件

    最后,我们可以使用read命令读取Linux系统上存储在文件中的数据。每调用一次read命令都会读取文件中的一行文本。当文件中没有可读的行时,read命令将以非零退出状态退出。

    我通过cat命令将内容传输给read来读取;

#!/bin/bash
# reading data from a file

count=1
cat test | while read line  #while命令使用read命令不断处理文件中的每一行,知道read命令以非零状态退出
do
    echo "Line $count: $line"
    count=$[ $count + 1 ]
done
echo "Finished processing the file"

shell脚本处理用户输入(代码片段)

编写的脚本需要能够与使用者进行交互。baseshell提供了一些不同的方法来从用户处获得数据,包括命令行参数、命令行选项以及直接从键盘读取输入的能力。命令行参数命令行参数是向shell脚本传递数据的最基本方法。如下... 查看详情

beego框架之请求数据处理(代码片段)

我们经常需要获取用户传递的数据,包括Get、POST等方式的请求,beego里面会自动解析这些数据,你可以通过如下方式获取数据:通过this.Getstring("获取用户输入")获取用户输入再通过this.Ctx.WriteString("输出用户输入的内... 查看详情

用户注册及登录功能(初级)(代码片段)

...功能。要求:1.使用while循环实现菜单的选择2.使用try异常处理解决用户输入非数字问题3.对用户输入功能选项编号越界进行处理4.用户注册信息存入列表中,每个用户使用字典类型封装5.用户注册需进行两次密码一致性验证,同时... 查看详情

07-输入(代码片段)

...n中,input会把接收到的任意用户输入的数据都当做字符串处理。password=input 查看详情

vba学习笔记错误处理(代码片段)

一下代码实现用户输入判断,出错可以一直重试。Subdemo() DimbirthdayAsDate OnErrorResumeNext'出错时忽略,继续向下运行。 Do birthday=InputBox("输入您的生日(yyyy-MM-dd)")'假设此处用户没有输入日期。 IfErr.Number<>0... 查看详情

异常处理(代码片段)

一、错误和异常1.错误代码运行前的语法或者逻辑错误语法错误(这种错误,根本过不了python解释器的语法检测,必须在程序执行前就改正)deftest:^SyntaxError:invalidsyntax 其他语法错误 逻辑错误#用户输入不完整(比如输入为... 查看详情

java小白入门200例06之用户输入处理(代码片段)

作者简介作者名:编程界明世隐简介:CSDN博客专家,从事软件开发多年,精通Java、JavaScript,博主也是从零开始一步步把学习成长、深知学习和积累的重要性,喜欢跟广大ADC一起打野升级,欢迎您关注&... 查看详情

异常处理(代码片段)

异常和错误程序中难免出现错误,而错误分成两种1.语法错误(这种错误,根本过不了python解释器的语法检测,必须在程序执行前就改正)#语法错误示范一if#语法错误示范二deftest:pass#语法错误示范三print(haha语法错误2.逻辑错误... 查看详情

vba学习笔记错误处理(代码片段)

一下代码实现用户输入判断,出错可以一直重试。Subdemo() DimbirthdayAsDate OnErrorResumeNext'出错时忽略,继续向下运行。 Do birthday=InputBox("输入您的生日(yyyy-MM-dd)")'假设此处用户没有输入日期。 IfErr.Number<>0... 查看详情

如何输入任何可见的单个字符,然后立即批处理cmd[复制](代码片段)

这个问题在这里已有答案: Howtousespecialcharactersinchoicecommand-BatchFile3回答 目标:我希望用户只键入一个字符(任何字符),然后脚本立即响应,无需额外按键“输入”键。如果用户键入“enter”键而没有先前... 查看详情

为什么用户的输入值在批处理文件中的代码中不起作用?[重复](代码片段)

...uesin.batnotworking1回答 操作系统是Windows10.我的批处理文件代码是:@echooff:startREMcheckiftherearemorethenoneargumentsifnot"%2"==""(echoToomanyparametersentered)ELSE(REMcheckifargumentoneisemptyif"%1"==""(ECHOEnterFileNameYourwanttoeditSET/Pname=ECHOYourNameis%name%)... 查看详情

异常处理专区:(代码片段)

异常和错误part1:程序中难免出现错误,而错误分成两种1.语法错误(这种错误,根本过不了python解释器的语法检测,必须在程序执行前就改正)#语法错误示范一if#语法错误示范二deftest:pass#语法错误示范三print(haha2.逻辑错误(逻... 查看详情

python3身份证号处理(代码片段)

身份证号处理描述18位身份证号码:第7、8、9、10位为出生年份(四位数),第11、第12位为出生月份,第13、14位代表出生日期,第17位代表性别,奇数为男,偶数为女。用户输入一个合法的身份证号,请输出用户的出生年月日,年... 查看详情

lq0255串的处理文本处理(代码片段)

...JavaC组H题题目描述在实际的开发工作中,对字符串的处理是最常见的编程任务。本题目即是要求程序对用户输入的串进行处理。具体规则如下:把每个单词的首字母变为大写。把数字与字母之间用下划线字符(_)... 查看详情

lq0255串的处理文本处理(代码片段)

...JavaC组H题题目描述在实际的开发工作中,对字符串的处理是最常见的编程任务。本题目即是要求程序对用户输入的串进行处理。具体规则如下:把每个单词的首字母变为大写。把数字与字母之间用下划线字符(_)... 查看详情

solr搜索流程(代码片段)

...字符串,根据用户的请求类型qt(查询为/select)选择请求处理器RequestHandler,根据用户输入的参数defType来选择一个查询解析器解析用户的查询串(默认使用RequestHander中配置的默认查询解析器),查询解析器解析完以后根据用户... 查看详情

libgdx输入处理手势捕获(代码片段)

Android游戏开发群:290051794Libgdx游戏开发框架交流群:261954621 触摸屏非常适合手势输入。一个手势可以是通过两个手指来变焦,点击,双击或长按等等。Libgdx提供了GestureDetector类来检测以下动作:1、 点击ÿ... 查看详情

python之异常处理(代码片段)

什么是错误?1.语法错误(这种错误,根本过不了python解释器的语法检测,必须在程序执行前就改正)#语法错误示范一if#语法错误示范二deftest:pass#语法错误示范三print(haha2.逻辑错误(逻辑错误)#用户输入不完整(比如输入为空)... 查看详情