Linux shell 处理输入

bash shell提供了一些不同的方法来从用户处获得数据,包括命令行参数(添加在命令后的数据)、命令行选项(可修改命令行为的单个字母)以及直接从键盘读取输入的能力。

一、命令行参数
向shell脚本传递数据的最基本方法是使用命令行参数。bash shell会将一些称为位置参数(positional parameter)的特殊变量分配给输入到命令行中的所有参数。这也包括shell所执行的脚本名称。位置参数变量是标准的数字:$0 是程序名,$1 是第一个参数,$2 是第二个参数,依次类推,直到第九个参数\(9 。在第9个变量之后,你必须在变量数字周围加上花括号,比如\){10} 。

例子:

#!/bin/bash

fac=1
for((num=1;num<=$1;num++))
do
  fac=$[$fac*$num]
done

echo result is:$fac

#!/bin/bash

result=$[$1*$2]

echo first param is:$1
echo second param is:$2

echo result is:$result

#!/bin/bash

echo hello,$1

如果参数中出现空白字符,则会出现问题:

必须要加引号:

#!/bin/bash

echo $10
echo $11

#!/bin/bash

echo the zero param is:$0

如果使用另一个命令来运行shell脚本,命令会和脚本名混在一起,出现在$0参数中。

#!/bin/bash

echo the zero param is:$(basename $0)

#!/bin/bash

name=$(basename $0)

if [ $name = 'add' ]; then
   result=$[$1+$2]
elif [ $name = 'mul' ]; then
  result=$[$1*$2]
fi

echo $result

如果执行脚本时不加参数则会出问题:

$#:命令行参数个数

例子:

#!/bin/bash


echo the param of number is:$#

既然$#表示参数个数,那么${$#}应该表示最后一个参数,

#!/bin/bash


echo the last param is:${$#}

从输出看到,${$#}不表示最后一个参数。

将${$#}换成${@: -1}:

#!/bin/bash

echo $#
echo the last param is: ${@: -1}

\(* 和\)@ 变量可以用来轻松访问所有的参数。这两个变量都能够在单个变量中存储所有的命令行参数。\(*变量会将命令行上提供的所有参数当作一个单词保存。这个单词包含了命令行中出现的每一个参数值。基本上\)* 变量会将这些参数视为一个整体,而不是多个个体。$@ 变量会将命令行上提供的所有参数当作同一字符串中的多个独立的单词。

#!/bin/bash

echo "测试\$*"

for item in "$*"
do
  echo $item
done


echo "测试\$@"

for item in "$@"
do
  echo $item
done

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

#!/bin/bash

while [ -n "$1" ]
do
  echo "$1"
  shift
done

可以一次性移动多个位置,只需要给 shift命令提供一个参数,指明要移动的位置数:

#!/bin/bash

while [ -n "$1" ]
do
  echo "$1"
  shift 2
done

二、命令行选项
选项是跟在单破折线后面的单个字母,它能改变命令的行为。

#!/bin/bash


for item in "$@"
do
   case $item in
     -a)
       echo option:$item;;
     -b)
       echo option:$item;;
     -c)
       echo option:$item;;
     *)
       echo unkown option;;
   esac
done

shell会用双破折线来表明选项列表结束。在双破折线之后,脚本就可以放心地将剩下的命令行参数当作参数。

#!/bin/bash


for item in "$@"
do
   case $item in
     -a)
       echo option:$item;;
     -b)
       echo option:$item;;
     -c)
       echo option:$item;;
     --)
       shift
       break;;
     *)
       echo unkown option:$item;;
   esac
   shift
done

echo param:

for item in $@
do
  echo $item
done

使用getopt解析选项和参数:

格式:

getopt optstring parameters

optstring 是这个过程的关键所在。它定义了命令行有效的选项字母,还定义了哪些选项字母需要参数值。首先,在optstring 中列出你要在脚本中用到的每个命令行选项字母。然后,在每个需要参数值的选项字母后加一个冒号。getopt命令会基于你定义的optstring 解析提供的参数。

例子:

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

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

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

如果指定了一个不在optstring 中的选项,默认情况下,getopt 命令会产生一条错误消息。如果想忽略这条错误消息,可以在命令后加-q选项。

例子:

#!/bin/bash

set -- $(getopt -q ab:c "$@")

while [ -n $1 ]
do
   case $1 in
     -a)
       echo option:$1;;
     -b) 
       param=$2
       echo option:$1,param is:$param
       shift;;
     -c)
       echo option:$1;;
     --)
      shift
      break;;
     *)
       echo unkown option:$1;;
   esac
   shift
done

echo start param:

for item in "$@"
do
 echo $item
done

set --是根据分隔符IFS,把值依次赋给$1,$2,$3。

test3 test4是同一个参数,但是被分成了两个,这是getopt存在的问题。

getopts和getopt很相似,但多了扩展功能。每次调用getopts时,它一次只处理命令行上检测到的一个参数。处理完所有的参数后,它会退出并返回一个大于0的退出状态码。

格式:

getopts optstring variable

optstring值类似于getopt命令中的那个。有效的选项字母都会列在optstring中,如果选项字母要求有个参数值,就加一个冒号。要去掉错误消息的话,可以在optstring 之前加一个冒号。getopts命令将当前参数保存在命令行中定义的variable 中。

getopts 命令会用到两个环境变量。如果选项需要跟一个参数值,OPTARG环境变量就会保存这个值。OPTIND环境变量保存了参数列表中getopts正在处理的参数位置。将命令行上找到的所有未定义的选项统一输出成问号。

#!/bin/bash

while getopts :ab:c opt
do
  case $opt in
    a)
     echo a option;;
    b)
     echo b option,param:$OPTARG;;
    c)
     echo c option;;
    *)
     echo unknown option:$opt;;
  esac
done

参数可以包含空格。

可以将选项和值合在一起。

#!/bin/bash

while getopts :ab:c opt
do
  case $opt in
    a)
     echo a option;;
    b)
     echo b option,param:$OPTARG;;
    c)
     echo c option;;
    *)
     echo unknown option:$opt;;
  esac
done

shift $[$OPTIND-1]

echo start handle param:

for param in "$@"
do
 echo $param
done

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

#!/bin/bash


read  -p  "Enter your name:"  name
echo "Hello $name"

#!/bin/bash


echo -n "Enter your name:"
read  name
echo "Hello $name"

read 命令会将提示符后输入的所有数据分配给单个变量,要么你就指定多个变量。输入的每个数据值都会分配给变量列表中的下一个变量。 如果变量数量不够,剩下的数据就全部分配给最后一个变量。

#!/bin/bash

read -p "Enter input:" first second

echo $first
echo $second

在read命令行中不指定变量,read 命令会将它收到的任何数据都放进特殊环境变量REPLY中:

#!/bin/bash

read -p "Enter input:"

echo $REPLY

#!/bin/bash

read -p "Enter input:" name

echo $REPLY
echo $name

read后面指定变量后,数据不会放入$REPLY中。

read -t 超时时间:可以指定read的超时时间。如果计时器过期,read命令会以非零退出状态码退出。

#!/bin/bash

if read -t 5 -p "Enter input:" name 
then
 echo "hello,$name"
else
 echo "Sorry,you not input"
fi

read -n 数字:read 命令来统计输入的字符数。当输入的字符达到预设的字符数时,就自动退出,将输入的数据赋给变量,无需按回车键。

#!/bin/bash

read -n 1 -p "Do you want to continue [Y/N]?" answer
echo
case $answer in
Y|y)
 echo Yes;;
N|n)
  echo No;;

esac

-s 选项可以避免在read命令中输入的数据出现在显示器上(实际上,数据会被显示,只是read 命令会将文本颜色设成跟背景色一样)。

#!/bin/bash

read -s -p "Enter password:" passwd
echo
echo "password:$passwd"

从文件中读取:
可以用read 命令来读取Linux系统上文件里保存的数据。每次调用read命令,它都会从文件中读取一行文本。当文件中再没有内容时,read命令会退出并返回非零退出状态码。其中最难的部分是将文件中的数据传给read命 令。最常见的方法是对文件使用cat命令,将结果通过管道直接传给含有read命令的while命令。

文件test:

The quick brown dog jumps over the lazy fox. 
This is a  test, this is only a test. O Romeo, Romeo!         
Wherefore art thou Romeo?

例子:

#!/bin/bash

file=$HOME/test
count=1

cat $file | while read line
do
 echo line $count:$line
 (( count++ ))
done

posted @ 2022-09-14 22:30  shigp1  阅读(669)  评论(0编辑  收藏  举报