Linux 命令 & shell 脚本之07(命令行参数&用户输入)

1.读取参数

位置参数变量是标准的数字:$0是程序名,$1是第一个参数,$2是第二个参数,依次类推,直到第九个参数$9
如果需要输入更多的命令行参数,则每个参数都必须用空格分开

#案例1
[oracle@DB02 myshell]$ cat test_input1.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

[oracle@DB02 myshell]$ ./test_input1.sh 5
 The factorial of 5 is 120

#案例2
[oracle@DB02 myshell]$ cat test_input2.sh 
#!/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.

[oracle@DB02 myshell]$ ./test_input2.sh 2 3
The first parameter is 2.
The second parameter is 3.
The total value is 6.

#案例3,在命令行上用文本字符串參數
[oracle@DB02 myshell]$ cat test_input3.sh 
#!/bin/bash 
# testing string parameters 
# 
echo Hello $1, glad to meet you.

[oracle@DB02 myshell]$ ./test_input3.sh xag
Hello xag, glad to meet you.

每个参数都是用空格分隔的,在参数值中包含空格,必须要用引号(单引号或双引号均可)
[oracle@DB02 myshell]$ ./test_input3.sh 'x ag'
Hello x ag, glad to meet you.

[oracle@DB02 myshell]$ ./test_input3.sh "x ag"
Hello x ag, glad to meet you.

如果脚本中命令行参数不止9个,仍然可以处理,需要稍微修改一下变量名。在第9个变量之后,必须在变量数字周围加上花括号,比如${10}

#案例4
[oracle@DB02 myshell]$ cat test_input4.sh 
#!/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

[oracle@DB02 myshell]$ ./test_input4.sh 1 2 3 4 5 6 7 8 9 10 11
The tenth parameter is 10
The eleventh parameter is 11
The total is 110

2.读取脚本名

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

[oracle@DB02 myshell]$ cat test_input5.sh 
#!/bin/bash 
# Testing the $0 parameter 
# 
echo The zero parameter is set to: $0
[oracle@DB02 myshell]$ 
[oracle@DB02 myshell]$ bash test_input5.sh 
The zero parameter is set to: test_input5.sh

[oracle@DB02 myshell]$ ./test_input5.sh
The zero parameter is set to: ./test_input5.sh

[oracle@DB02 myshell]$ /home/oracle/myshell/test_input5.sh
The zero parameter is set to: /home/oracle/myshell/test_input5.sh

把脚本的运行路径给剥离掉。另外,还要删除与脚本名混杂在一起的命令,basename命令会返回不包含路径的脚本名
[oracle@DB02 myshell]$ cat test_input5.sh 
#!/bin/bash 
# Testing the $0 parameter 
# 
echo The zero parameter is set to: $0

name=$(basename $0) 
echo 
echo The script name is: $name

---------------------------------------------------------------------------------------------
[oracle@DB02 myshell]$ bash test_input5.sh 
The zero parameter is set to: test_input5.sh

The script name is: test_input5.sh
---------------------------------------------------------------------------------------------
[oracle@DB02 myshell]$ ./test_input5.sh
The zero parameter is set to: ./test_input5.sh

The script name is: test_input5.sh
---------------------------------------------------------------------------------------------
[oracle@DB02 myshell]$ /home/oracle/myshell/test_input5.sh
The zero parameter is set to: /home/oracle/myshell/test_input5.sh

The script name is: test_input5.sh
---------------------------------------------------------------------------------------------

3.测试参数

在使用参数前检查其中是否存在数据
[oracle@DB02 myshell]$ cat test_input7.sh
#!/bin/bash 
# testing parameters before use 
# 
if [ -n "$1" ] 
then 
 echo Hello $1, glad to meet you. 
else 
 echo "Sorry, you did not identify yourself. " 
fi


[oracle@DB02 myshell]$ ./test_input7.sh xag
Hello xag, glad to meet you.

[oracle@DB02 myshell]$ ./test_input7.sh
Sorry, you did not identify yourself. 

5.参数统计

特殊变量$#含有脚本运行时携带的命令行参数的个数
[oracle@DB02 myshell]$ cat test_input8.sh 
#!/bin/bash 
# getting the number of parameters 
# 
echo There were $# parameters supplied

[oracle@DB02 myshell]$ ./test_input8.sh 
There were 0 parameters supplied

[oracle@DB02 myshell]$ ./test_input8.sh 1 2
There were 2 parameters supplied

[oracle@DB02 myshell]$ ./test_input8.sh 1 2 3 4 5 6 7 8 9 10
There were 10 parameters supplied

[oracle@DB02 myshell]$ ./test_input8.sh 'x xag'
There were 1 parameters supplied
  1. 獲取最後一個參數
$#变量含有参数的总数,那么变量${$#}就代表了最后一个命令行参数变量,其實不是,正確是  ${!#}

[oracle@DB02 myshell]$ cat test_input8.sh 
#!/bin/bash 
# getting the number of parameters 
# 
echo There were $# parameters supplied

params=$# 
echo 
echo The last parameter is $params 
echo The last parameter is ${!#}

---------------------------------------------------------------------------------------------
[oracle@DB02 myshell]$ ./test_input8.sh 2 4 6
There were 3 parameters supplied

The last parameter is 3
The last parameter is 6
---------------------------------------------------------------------------------------------
[oracle@DB02 myshell]$ ./test_input8.sh
There were 0 parameters supplied

The last parameter is 0
The last parameter is ./test_input8.sh
---------------------------------------------------------------------------------------------
[oracle@DB02 myshell]$ ./test_input8.sh 'x xag'
There were 1 parameters supplied

The last parameter is 1
The last parameter is x xag

重要的是要注意,当命令行上没有任何参数时,$#的值为0,params变量的值也一样,但${!#}变量会返回命令行用到的脚本名

7.抓取所有的參數

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

[oracle@DB02 myshell]$ cat test_input11.sh 
#!/bin/bash 
# testing $* and $@ 
# 
echo 
echo "Using the \$* method: $*" 
echo 
echo "Using the \$@ method: $@"
---------------------------------------------------------------------------------------------
[oracle@DB02 myshell]$ ./test_input11.sh 2 4 6 xag

Using the $* method: 2 4 6 xag

Using the $@ method: 2 4 6 xag
---------------------------------------------------------------------------------------------

通过使用for命令遍历 $@
---------------------------------------------------------------------------------------------
[oracle@DB02 myshell]$ cat test_input11.sh 
#!/bin/bash 
# testing $* and $@ 
# 
echo 
echo "Using the \$* method: $*" 
echo 
echo "Using the \$@ method: $@"

echo 
count=1 
#
for param in "$@"; do 
 echo "\$@ Parameter #$count = $param" 
 count=$[ $count + 1 ] 
done
---------------------------------------------------------------------------------------------
[oracle@DB02 myshell]$ ./test_input11.sh 2 4 6 xag

Using the $* method: 2 4 6 xag

Using the $@ method: 2 4 6 xag

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

[oracle@DB02 myshell]$ cat test_input13.sh 
#!/bin/bash 
# demonstrating the shift command 
echo 
count=1 
while [ -n "$1" ]; do 
 echo "Parameter #$count = $1" 
 count=$[ $count + 1 ] 
 shift 
done 
---------------------------------------------------------------------------------------------
[oracle@DB02 myshell]$ ./test_input13.sh 2 4 6 xag

Parameter #1 = 2
Parameter #2 = 4
Parameter #3 = 6
Parameter #4 = xag

可以一次性移动多个位置,只需要给shift命令提供一个参数
[oracle@DB02 myshell]$ cat test_input15.sh 
#!/bin/bash 
# demonstrating the shift command 
count=1 
while [ -n "$1" ]; do 
 echo "Parameter #$count = $1" 
 count=$[ $count + 2 ] 
 shift 2 
done 
---------------------------------------------------------------------------------------------
[oracle@DB02 myshell]$ ./test_input15.sh 1 2 3 4 5 6 7 8
Parameter #1 = 1
Parameter #3 = 3
Parameter #5 = 5
Parameter #7 = 7

9.处理选项

处理简单选项(使用shift命令)
[oracle@DB02 myshell]$ cat test_input16.sh 
#!/bin/bash 
# extracting command line options as parameters 
# 
echo 
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
---------------------------------------------------------------------------------------------
[oracle@DB02 myshell]$ ./test_input16.sh  -a -b -c -d

Found the -a option
Found the -b option
Found the -c option
-d is not an option

分离参数和选项 (Linux中处理这个问题的标准方式是用特殊字符来将二者分开) 个特殊字符是双破折线 --

shell会用双破折线来表明选项列表结束。在双破折线之后,脚本就可以放心地将剩下的命令行参数当作参数
[oracle@DB02 myshell]$ cat test_input16.sh 
#!/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 $@; do 
 echo "Parameter #$count: $param" 
 count=$[ $count + 1 ] 
done

[oracle@DB02 myshell]$ ./test_input16.sh  -a -b -c 1 2 3
Found the -a option
Found the -b option
Found the -c option
1 is not an option
2 is not an option
3 is not an option

结果说明在处理时脚本认为所有的命令行参数都是选项。接下来,进行同样的测试,只是这次会用双破折线来将命令行上的选项和参数划分开来
[oracle@DB02 myshell]$ ./test_input16.sh  -a -b -c -- 1 2 3
Found the -a option
Found the -b option
Found the -c option
Parameter #1: 1
Parameter #2: 2
Parameter #3: 3
  1. 处理带值的选项
有些选项会带上一个额外的参数值。在这种情况下,命令行看起来像下面这样:
$ ./test17.sh -a -b test1 -d

[oracle@DB02 myshell]$ cat test_input17.sh
#!/bin/bash 
# extracting command line options and values 
# 
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

[oracle@DB02 myshell]$ ./test_input17.sh -a -b test1 -d
Found the -a option
Found the -b option, with parameter value test1
-d is not an option

[oracle@DB02 myshell]$ ./test_input17.sh -b test1 -a -d
Found the -b option, with parameter value test1
Found the -a option
-d is not an option

11.getopt命令处理命令行选项和参数

getopt命令格式如下:
getopt optstring parameters

案例 1 (基于提供的optstring进行解析,并插入双破折线来分隔行中的额外参数)
[oracle@DB02 myshell]$  getopt abc -a -b para1 para2
 -a -b -- para1 para2

[oracle@DB02 myshell]$  getopt abc -a -b -c para1 para2
 -a -b -c -- para1 para2

[oracle@DB02 myshell]$  getopt abc -a -b para1 -c para2
 -a -b -c -- para1 para2

#冒号(:)被放在了字母b后面,因为b选项需要一个参数值
[oracle@DB02 myshell]$ getopt ab:c -a -b para1 -c para2
 -a -b para1 -c -- para2

#自动将-bc选项分成两个单独選項
[oracle@DB02 myshell]$  getopt abc -a -bc para1 para2
 -a -b -c -- para1 para2

#自动将-abc选项分成3个单独選項
[oracle@DB02 myshell]$  getopt abc -abc para1 para2
 -a -b -c -- para1 para2

[oracle@DB02 myshell]$  getopt abc -a -b -d para1 para2
getopt: invalid option -- 'd'
 -a -b -- para1 para2

#加上 -q选项 忽略上面的錯誤
[oracle@DB02 myshell]$  getopt -q abc -a -b -d para1 para2
 -a -b -- 'para1' 'para2'

12.在脚本中使用getopt

方法是用getopt命令生成的格式化后的版本来替换已有的命令行选项和参数。用set命令能够做到
set命令的选项之一是双破折线(--),它会将命令行参数替换成set命令的命令行值。
然后,该方法会将原始脚本的命令行参数传给getopt命令,之后再将getopt命令的输出传
给set命令,用getopt格式化后的命令行参数来替换原始的命令行参数,看起来如下所示。
set -- $(getopt -q ab:c "$@")

[oracle@DB02 myshell]$ cat test_input18.sh 
#!/bin/bash 
# Extract command line options & values with getopt 
# 
set -- $(getopt -q ab:c "$@") 
# 
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

[oracle@DB02 myshell]$ ./test_input18.sh -b test1 -ac test2 test3
Found the -b option, with parameter value 'test1'
Found the -a option
Found the -c option
Parameter #1: 'test2'
Parameter #2: 'test3'

#有問題 (getopt命令并不擅长处理带空格和引号的参数值。它会将空格当作参数分隔符,而不是根据双引号将二者当作一个参数)
[oracle@DB02 myshell]$ ./test_input18.sh -b test1 -ac 'x ag' test3
Found the -b option, with parameter value 'test1'
Found the -a option
Found the -c option
Parameter #1: 'x
Parameter #2: ag'
Parameter #3: 'test3'
  1. 使用更高级的 getopts (解決上面遇到的 問題)
getopts命令的格式如下:
getopts optstring variable
optstring值类似于getopt命令中的那个。有效的选项字母都会列在optstring中,如果
选项字母要求有个参数值,就加一个冒号。要去掉错误消息的话,可以在optstring之前加一个
冒号。getopts命令将当前参数保存在命令行中定义的variable中.

getopts命令会用到两个环境变量。如果选项需要跟一个参数值,OPTARG环境变量就会保
存这个值。OPTIND环境变量保存了参数列表中getopts正在处理的参数位置。这样你就能在处
理完选项之后继续处理其他命令行参数了.

案例 1
注意在本例中case语句的用法有些不同。getopts命令解析命令行选项时会移除开头的单破折线,所以在case定义中不用单破折线
[oracle@DB02 myshell]$ cat test_input19.sh
#!/bin/bash 
# simple demonstration of the getopts command 
# 
echo 
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 "Unknown option: $opt";; 
 esac 
done
echo "OPTIND = "  $OPTIND

[oracle@DB02 myshell]$ ./test_input19.sh -a -b test1 -c

Found the -a option
Found the -b option, with value test1
Found the -c option
OPTIND =  5

[oracle@DB02 myshell]$ ./test_input19.sh -ab test1 -c

Found the -a option
Found the -b option, with value test1
Found the -c option
OPTIND =  4


案例2
[oracle@DB02 myshell]$ cat test_input20.sh
#!/bin/bash 
# Processing options & parameters with getopts 
# 
echo 
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 "Unknown option: $opt" ;; 
 esac 
done 
# 
echo "OPTIND - 1 = " $[ $OPTIND -1 ]
shift $[ $OPTIND - 1 ] 
# 
echo 
count=1 
for param in "$@"; do 
 echo "Parameter $count: $param" 
 count=$[ $count + 1 ] 
done
---------------------------------------------------------------------------------------------
[oracle@DB02 myshell]$ ./test_input20.sh -b test1 -ac xag test3

Found the -b option, with value test1
Found the -a option
Found the -c option
OPTIND - 1 =  3

Parameter 1: xag
Parameter 2: test3
---------------------------------------------------------------------------------------------
[oracle@DB02 myshell]$ ./test_input20.sh -b test1 -a -c xag test3

Found the -b option, with value test1
Found the -a option
Found the -c option
OPTIND - 1 =  4

Parameter 1: xag
Parameter 2: test3
---------------------------------------------------------------------------------------------
[oracle@DB02 myshell]$ ./test_input20.sh -b test1 -a -c 'x ag' test3

Found the -b option, with value test1
Found the -a option
Found the -c option
OPTIND - 1 =  4

Parameter 1: x ag
Parameter 2: test3

14.获得用户输入

案例1
[oracle@DB02 myshell]$ cat test_read1.sh 
#!/bin/bash 
# testing the read command 
# 
echo -n "Enter your name: " 
read name 
echo "Hello $name, welcome to my program. "

注意,生成提示的echo命令使用了-n选项。该选项不会在字符串末尾输出换行符,允许脚本用户紧跟其后输入数据
read命令会将姓和名保存在同一个变量中

[oracle@DB02 myshell]$ ./test_read1.sh 
Enter your name: x ag
Hello x ag, welcome to my program.

read命令包含了-p选项,允许你直接在read命令行指定提示符
[oracle@DB02 myshell]$ cat test_read1.sh 
#!/bin/bash 
# testing the read command 
# 
#echo -n "Enter your name: " 
#read name 
read -p "Enter your name: " name
echo "Hello $name, welcome to my program. "

[oracle@DB02 myshell]$ ./test_read1.sh 
Enter your name: xag
Hello xag, welcome to my program. 

指定多个变量。输入的每个值都会分配给变量列表中的下一个变量。如不够,剩下的数据就全部分配给最后一个变量
[oracle@XAG143 myshell]$ cat test_read2.sh 
#!/bin/bash
# entering multiple variables 
# 
read -p "Enter your name: " first last 
echo "Checking data for $last, $first…"

[oracle@XAG143 myshell]$ ./test_read2.sh 
Enter your name: x ag
Checking data for ag, x…

在read命令行中不指定变量。如果是这样,read命令会将它收到的任何数据都放进特殊环境变量REPLY中
$ cat test24.sh
#!/bin/bash 
# Testing the REPLY Environment variable 
# 
read -p "Enter your name: " 
echo 
echo Hello $REPLY, welcome to my program. 

$ ./test24.sh
Enter your name: Christine
Hello Christine, welcome to my program.

用-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: 
Sorry, too slow!

让read命令来统计输入的字符数。当输入的字符达到预设的字符数时,就自动退出,将输入的数据赋给变量
本例中将-n选项和值1一起使用,告诉read命令在接受单个字符后退出。只要按下单个字符回答后,
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 
          echo "fine, continue on…";; 
  N | n) echo 
         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

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

$ cat test28.sh 
#!/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" 

$ cat 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? 

$ ./test28.sh
Line 1: The quick brown dog jumps over the lazy fox. 
Line 2: This is a test, this is only a test. 
Line 3: O Romeo, Romeo! Wherefore art thou Romeo? 
Finished processing the file

$ cat test29.sh 
#!/bin/bash 
# reading data from a file 
# 
exec 0< test
count=1 
while read line; do 
 echo "Line $count: $line" 
 count=$[ $count + 1] 
done 
echo "Finished processing the file" 

[oracle@DB02 myshell]$ ./test29.sh 
Line 1: The quick brown dog jumps over the lazy fox.
Line 2: This is a test, this is only a test.
Line 3: O Romeo, Romeo! Wherefore art thou Romeo?
Finished processing the file

你可能感兴趣的:(Linux 命令 & shell 脚本之07(命令行参数&用户输入))