14 linux处理用户输入shell脚本

文章目录

    • 14.处理用户输入
      • 14.1 命令行参数
      • 14.2 特殊参数变量
      • 14.3 移动变量
      • 14.4 处理选项
      • 14.5 选项标准化
      • 14.6 获得用户输入

14.处理用户输入

14.1 命令行参数

向addem传递两个参数10 30

./addem 10 30

读取位置参数:$0是程序名,$1$9是第一个到第九个参数,之后的参数需要${10}这种才可以。参数与参数之间按照空格分开。

#!/bin/bash
#实现参数读取并做乘法
total=$[ $1 * $2 ]
echo "The first param is $1"
echo "The second param is $2"
echo "The total value is $total"

echo "The second param is ${10}"

读取脚本名:$0传递的是完整的脚本路径,使用basename得到不包含路径的脚本名,从而根据不同的脚本名实现不同的功能。

#!/bin/bash
#得到脚本的路径名和脚本名
path_name=$0
script_name=$(basename $0)

echo "The path of script is $path_name"
echo "The script name is $script_name"

测试参数: 脚本不加参数运行,会产生错误信息,因此最好添加相关参数测试
错误信息描述
使用-n测试参数中是否有数据

#!/bin/bash
#检测参数1是否正常输入参数
if [ -n "$1" ]
then
  echo "你输入的第一个参数为 $1 "
else
  echo "你没有输入任何的参数"
fi

14.2 特殊参数变量

参数统计
有些记录命令行的参数相关变量,如$#是记录命令行参数的总的个数

#!/bin/bash
#测试参数总的个数,有两个就做加法,否则就报错
if [ $# -ne 2 ]
then
  echo "Usage: $(basename $0) a b"
  echo
else
  total=$[ $1 + $2 ]
  echo
  echo "The total is $total"
  echo
fi

既然$#是记录了总的个数,那么${$#}应该代表最后一个命令行参数,但是不是这样的,${!#}才是正确的得到最后一个参数变量。

#!/bin/bash
#测试得到最后一个参数
echo "The last param is ${$#}"
echo "The last param is ${!#}"

运行结果

抓取所有数据
$*:所有参数合并为一个整体的字符串
$@:提供所有参数的独立字符串

#!/bin/bash
#测试$*和$@
count=1
for param in $*
  echo "\$* parameter #$count = $param"
  count=$[ $count + 1 ]
done

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

运行结果:
测试
貌似和我们介绍的有所不同,好吧,注意我们在遍历的时候写明:

for param in $@

$*$@两个的区别只能从"$*""$@"看出来,即写做

for param in "$*"
for param in "$@"

最后的执行结果为
真正的结果

14.3 移动变量

在你不知道到底有多少个参数的时候,你可以使用shift将之后变量的值转移到之前,如$2转移到$1,同时$1就被销毁了。

#!/bin/bash
#简单测试shift
count=1
while [ -n "$1" ]
do
  echo "Parameter #$count = $1"
  count=$[ $count + 1 ]
  shift
done     

注意shift n表示具体移动多少个参数

14.4 处理选项

处理简单的选项
使用case提取参数并判定是否为某个选项

#!/bin/bash
#使用shift依次判断每个参数是否为选项
count=1
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 the option" ;;
  esac
  shift
done

运行结果:
运行结果
分离参数和选项
如果一个脚本既要使用参数又要使用选项,这个时候需要一个特殊的参数帮助辨识哪些是参数哪些是选项,这里使用"–"来分离。

#!/bin/bash
#处理选项
count=1
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 the option" ;;
  esac
  shift
done

#处理参数
count=1
for param in "$@"
do
  echo "Parameter #$count: $param"
  count=$[ $count + 1 ]
done

执行结果:
14 linux处理用户输入shell脚本_第1张图片
处理带值的选项
例如下面这个例子,test1应该是为-a这个选项服务的

./testing.sh -a test1 -b -c -d test2

只需要在对应的选项插入读取参数的相关语句

#!/bin/bash
#处理选项
count=1
while [ -n "$1" ]
do
  case "$1" in
  -a) echo "Found the -a option" ;;
  -b) param="$2"     #读取-b之后的参数
      echo "Found the -b option with the param $param" 
      shift;;        #跳过-b之后的这个参数
  -c) echo "Found the -c option" ;;
  --) shift   #只是为了跳过--这个参数
      break;;
   *) echo "$1 is not the option" ;;
  esac
  shift
done

#处理参数
count=1
for param in "$@"
do
  echo "Parameter #$count: $param"
  count=$[ $count + 1 ]
done

运行结果
14 linux处理用户输入shell脚本_第2张图片
上述的命令只能处理单个选项,对于复合选项毫无能力,因此介绍下面的getopt命令

14.5 选项标准化

getopt命令
getopt命令格式如下

getopt optstring parameters

optstring中列出你要在脚本中用到的每个命令行选项字母。然后,在每个需要参数值的选项字母后加一个冒号。getopt命令会基于你定义的optstring解析提供的参数。
例如:

#ab:cd说明有4个选项,其中b需要有参数
 $getopt ab:cd -a -b test1 -cd test2 test3 
 -a -b test1 -c -d -- test2 test3

如果使用了没有声明的参数

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

可以使用-q忽略这个参数

$getopt -q ab:cd -a -b test1 -cde test2 test3 
 -a -b 'test1' -c -d -- 'test2' 'test3'

脚本中使用getopt
仔细思考一下,使用getopt可以得到格式化的输入。但是在脚本中执行时,无法将格式化的输入作为输入执行脚本。因此我们使用set --,它会将格式化后的命令替换掉原始的命令。

#!/bin/bash
#处理输入命令,相比上一个实例代码,只多了下面这行
set -- $(getopt -q ab:cd "$@")
#处理选项
count=1
while [ -n "$1" ]
do
  case "$1" in
  -a) echo "Found the -a option" ;;
  -b) param="$2"     #读取-b之后的参数
      echo "Found the -b option with the param $param" 
      shift;;        #跳过-b之后的这个参数
  -c) echo "Found the -c option" ;;
  --) shift   #只是为了跳过--这个参数
      break;;
   *) echo "$1 is not the option" ;;
  esac
  shift
done

#处理参数
count=1
for param in "$@"
do
  echo "Parameter #$count: $param"
  count=$[ $count + 1 ]
done

运行结果
14 linux处理用户输入shell脚本_第3张图片
但是这个代码仍然存在问题,无法合理的处理带空格和引号的参数值
14 linux处理用户输入shell脚本_第4张图片
使用更高级的optgets
getopts命令格式:

getopts optstring variable

optstring值:
有效的选项字母都会列在optstring中,如果选项字母要求有个参数值,就加一个冒号。要去掉错误消息的话,可以在optstring之前加一个冒号。

getopts命令:
将当前参数保存在命令行中定义的variable中。

两个重要的环境变量
OPTARG环境变量就会保存选项后的参数值。

OPTIND环境变量保存了参数列表中getopts正在处理的参数位置。这样你就能在处理完选项之后继续处理其他命令行参数了。

示例代码:

#!/bin/bash
#使用getopts得到选项参数分割,注意case下面的选项不是-a),并且是遍历完所有参数之后才实现位置转移的
while getopts :ab:cd opt
do
   case "$opt" in
   a) echo "This is -a option";;
   b) echo "This is -b option with value $OPTARG";;
   c) echo "This is -c option";;
   d) echo "This is -d option";;
   *) echo "Unknown option:$opt" ;;
   esac
done

#跳过当前已经处理完毕的参数
shift $[ $OPTIND - 1 ]

#遍历参数
count=1
for param in "$@"
do
   echo "Parameter $count: $param"
   count=$[ $count + 1 ]
done

选项标准化:
Linux命令对于关键的参数已经有具体的意义了,参照
14 linux处理用户输入shell脚本_第5张图片

14.6 获得用户输入

基本读取
使用read从标准输入得到变量值

#!/bin/bash
#-n表示不换行得到输入
echo -n "Enter your name:"
read name
echo "Hello $name, welcome to my program."

#read -p可以输出一些提示信息得到单个输入
read -p "Please enter your age: " age
days=$[ $age * 365 ]
echo "That makes you over $days days old;"

#read 得到多个输入
read -p "Please enter your first and last: " first last
echo "Checking data for $first, $last..."

#如果不指定变量,所有输入会保存在REPLY中
read -p "Enter the name which will save in:"
echo "hello, welcome to $REPLY"

超时判断
为了防止一直等待,使用-t设置等待的秒数,超时之后返回非0退出码。
也可以设置-n num读取指定数量的输入退出。

#!/bin/bash
#设置超时时间的输入
if read -t 5 -p "Please enter your name:" name
then
   echo "Hello $name, welcome to my script"
else
   echo "Sorry, too slow!"
fi
#设置指定数量的输入

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 scipt" 

14 linux处理用户输入shell脚本_第6张图片
隐藏方式读取
-s选项可以避免在read输入的数据出现在显示器上

#!/bin/bash
read -s -p "Enter your password: " pass
echo
echo "Is your password really $pass? "

从文件读取

#!/bin/bash 
# reading data from a file 
# 
count=1 
cat test | while read line 
do 
   echo "Line $count: $line" 
   count=$[ $count + 1] 
done 
echo "Finished processing the file"

你可能感兴趣的:(bash,linux,开发语言)