常用参数变量

一些常用的参数变量,可以获取传给命令行的参数。

  1. $0 脚本名,带有路径
  2. # 使用 basename 只获取名称
  3. $(basename $0)
  4. $1 ... $9, ${10}, ${11} ...
  5. # 在使用参数前注意检查是否存在
  6. if [ -n "$1" ]
  7. then
  8. ...
  9. fi
  10. # 特殊参数变量
  11. $# 获取参数的个数
  12. ${!#} 获取最后一个参数。如果没有参数,${!#} 返回的是脚本的名称
  13. # 这种方法也是返回参数的个数,如果没有参数,返回 0
  14. last=$#
  15. echo "The parameter number is $last"
  16. $* 把所有的输入当作一个整体
  17. $@ 会分割输入的参数,可使用 for 循环分别获取
  18. for param in "$@"
  19. do
  20. ...
  21. done

传给命令行的参数如果有空格,需要使用引号:

  1. $ ./test.sh "Rich Parker"

shift 命令移动变量

作用:将每个参数变量向左移动一个位置。变量 $0 的值不会变。

如果某个参数被移除,它的值就被丢弃了,无法再恢复。

  1. #!/bin/bash
  2. # shift 后面也可以跟参数,表示一次移动多个
  3. count=1
  4. while [ -n "$1" ]
  5. do
  6. echo "Parameter #$count = $1"
  7. count=$((count+1))
  8. shift
  9. done
  10. # 使用 shift 之后,就无法再获取参数的值了
  11. echo "The second parameter is $2"
  12. # 运行结果是:
  13. $ ./test21-shift.sh rich barbara katie jessica
  14. Parameter #1 = rich
  15. Parameter #2 = barbara
  16. Parameter #3 = katie
  17. Parameter #4 = jessica
  18. The second parameter is

处理选项

命令行选项后面可以带参数;

shell 会用双破折号来表明选项列表结束,在双破折号之后,就可以将剩下的命令行参数当作参数;

  1. while [ -n "$1" ]
  2. do
  3. case "$1" in
  4. -a) echo "Found the -a option" ;;
  5. -b) echo "Found the -b option, with parameter value $2"
  6. shift ;;
  7. -c) echo "Found the -c option" ;;
  8. # 使用 -- 把命令选项和参数分隔开
  9. --) shift
  10. break;;
  11. *) echo "$1 is not an option";;
  12. esac
  13. # 移动变量
  14. shift
  15. done
  16. # 读取参数
  17. count=1
  18. for param in "$@"
  19. do
  20. echo "Parameter #$count: $param"
  21. count=$((count+1))
  22. done
  23. # 测试
  24. $ sh testsh.sh -a -b 23 -c -d -- param1 param2
  25. Found the -a option
  26. Found the -b option, with parameter value 23
  27. Found the -c option
  28. -d is not an option
  29. Parameter #1: param1
  30. Parameter #2: param2

弊端,将多个选项放在一起就不能用了,比如 -ab

使用 getopt

getopt optstring parametrs

optstring 中列出要在脚本中用到的每个命令行选项字母,在每个需要参数值的选项字母后加一个冒号。

  1. $ getopt ab:cd -a -b test1 -cde test2 test3
  2. getopt: illegal option -- e
  3. -a -b test1 -c -d -- test2 test3

如果指定了一个不在 optstring 中的选项,会抛出错误信息,使用 -q 选项可以忽略。

在脚本中使用 getopt 命令:

set 命令的选项之一是双破折号(—),它会将命令行参数替换成 set 命令的命令行值。

  1. # 使用 getopt 处理命令参数
  2. # getopt 处理带空格的参数有问题
  3. set -- $(getopt -q ab:cd "$@")
  4. # 剩下的和上面的处理一样

弊端,处理带空格的参数值有问题,它会将空格当作参数分隔符,而不是根据引号将二者当作一个参数。比如下面这个:

  1. $ ./test.sh -a -b test1 -cd "test2 test3" test4
  2. Found the -a option
  3. Found the -b option, with parameter value test1
  4. Found the -c option
  5. -d is not an option
  6. Parameter #1: test2
  7. Parameter #2: test3
  8. Parameter #3: test4

使用 getopts

getopts optstring variable

每次调用它时,只处理命令行上检测到的一个参数。处理完所有的参数之后,会退出并返回一个大于 0 的退出状态码。

要去掉错误消息的话,可以在 optstring 之前加一个冒号。

用到两个环境变量。如果选项需要跟一个参数值,OPTARG 环境变量就会保存这个值。OPTIND 环境变量保存了参数列表中 getopts 正在处理的参数位置。

  1. #!/bin/bash
  2. while getopts :ab:c opt
  3. do
  4. case "$opt" in
  5. # 这边不需要单破折号
  6. a) echo "Found the -a option" ;;
  7. b) echo "Found the -b option, with value $OPTARG" ;;
  8. c) echo "Found the -c option" ;;
  9. *) echo "Unknown option: $opt"
  10. esac
  11. done
  12. # 移动参数
  13. shift $((OPTIND - 1))
  14. count=1
  15. for param in "$@"
  16. do
  17. echo "Parameter #$count: $param"
  18. count=$((count+1))
  19. done
  20. # 使用示例
  21. # 选项可以放在一起
  22. $ ./test23.sh -ab test1 -c
  23. Found the -a option
  24. Found the -b option, with value test1
  25. Found the -c option
  26. # 参数中可以有空格
  27. $ ./test23.sh -ab "test test" -c
  28. Found the -a option
  29. Found the -b option, with value test test
  30. Found the -c option
  31. # 参数和选项不用空格分开
  32. $ ./test23.sh -abtest
  33. ound the -a option
  34. Found the -b option, with value test
  35. # 会将没有定义的选项输出为问号
  36. $ ./test23.sh -acde
  37. Found the -a option
  38. Found the -c option
  39. Unknown option: ?
  40. Unknown option: ?

将选项标准化

有些字母选项在 Linux 世界里已经有了某种程度的标准含义。下表列出了一些常用的 Linux 命令选项:
image.png

获取用户输入 read

使用 read 命令:
-p 后面跟提示信息,即在输入前打印提示信息
-s 安静模式,在输入字符时不再屏幕上显示,例如login时输入密码
-n 后跟一个数字,定义输入文本的长度
-t 后面跟秒数,定义输入字符的等待时间
-r 屏蔽\,如果没有该选项,则\作为一个转义字符,有的话 \就是个正常的字符了

  1. read name
  2. echo "Your name is $name"
  3. # 使用 -p 参数
  4. read -p "Please input your name: " name
  5. echo "Your name is $name"
  6. # read 一次性读入多个变量
  7. read -p "please input two number: " a b
  8. echo "The sum of the two numbers is: $((a+b))"
  9. # 使用 -s 参数,隐藏输入内容
  10. read -s -p "Please input your password: " password
  11. echo "Is your password really $password?"
  12. # read 后面不指定变量,会放在 REPLY 环境变量中
  13. read -p "Enter your name: "
  14. echo "Your name is $REPLY"
  15. # 使用 -t 指定等待的秒数
  16. if read -t 5 -p "Please enter your name: " name
  17. then
  18. echo "Hello $name"
  19. else
  20. echo "Sorry, too slow!"
  21. fi
  22. # 使用 -n 指定输入的字符数。输入的字符数达到指定的值,就会自动回车完成输入
  23. read -n1 -p "Do you want to continue [Y/N]? " answer
  24. case $answer in
  25. Y | y) echo
  26. echo "fine, continue on...";;
  27. N | n) echo
  28. echo "Ok, goodbye"
  29. exit;;
  30. esac

读取文件

可以用 read 命令来读取Linux系统上文件里保存的数据。每次调用 read 命令,它都 会从文件中读取一行文本。当文件中再没有内容时,read命令会退出并返回非零退出状态码。

  1. $ cat test25-read-file.sh
  2. #!/bin/bash
  3. count=1
  4. cat states | while read line
  5. do
  6. echo "Line $count: $line"
  7. count=$((count+1))
  8. done
  9. echo "Finished processing the file"
  10. $ cat states
  11. Alabama
  12. Alaska
  13. Arizona
  14. Arkasas
  15. California
  16. New York
  17. $ sh test25-read-file.sh
  18. Line 1: Alabama
  19. Line 2: Alaska
  20. Line 3: Arizona
  21. Line 4: Arkasas
  22. Line 5: California
  23. Finished processing the file

另一个方式:

  1. $ cat test25-read-file2.sh
  2. #!/bin/bash
  3. input="users.csv"
  4. while IFS=',' read -r userid name
  5. do
  6. echo "adding $userid"
  7. useradd -c "$name" -m "$userid"
  8. done < "$input"
  9. $ cat users.csv
  10. rich,Richard Blum
  11. christine,Christine Bresnahan
  12. barbara,Barbara Blum
  13. $ sh test25-read-file2.sh
  14. adding rich
  15. adding christine
  16. adding barbara
  17. # 查看刚才创建的账号
  18. $ tail -3 /etc/passwd
  19. rich:x:1001:1001:Richard Blum:/home/rich:/bin/bash
  20. christine:x:1002:1002:Christine Bresnahan:/home/christine:/bin/bash
  21. barbara:x:1003:1003:Barbara Blum:/home/barbara:/bin/bash