linghaiyan 发表于 2018-8-26 11:30:38

Shell脚本编程基础——Linux基本命令(11)

1.Shell脚本基础
(1)shell脚本
  包含一些命令或声明,并符合一定格式的文本文件
  格式要求:首行shebang机制
  #!/bin/bash
  #!/usr/bin/python
  #!/usr/bin/perl
(2)格式要求
  脚本代码开头约定:
  1、第一行一般为调用使用的语言
  2、程序名,避免更改文件名为无法找到正确的文件
  3、版本号
  4、更改后的时间
  5、作者相关信息
  6、该程序的作用,及注意事项
  7、最后是各版本的更新简要说明(也可以不写)

  其实最重要的是第一行,其他行也可以不写,但是为了一个良好的变成习惯,建议还是写上。
(3)脚本调试
  检测脚本中的语法错误
  bash -n/path/to/some_script
  调试执行
  bash -x/path/to/some_script

  会一条一条的调试执行,可以找出哪一句错误了

  如图,显示着最后一条有错误
2.变量
(1)变量介绍
  作用:
  1、数据存储格式
  2、参与的运算
  3、表示的数据范围
  类型:
  字符
  数值:整型、浮点型
  变量命名法则:
  1、不能使程序中的保留字:例如if, for
  2、只能使用数字、字母及下划线,且不能以数字开头
  3、见名知义
  4、统一命名规则:驼峰命名法
(2)bash中变量的种类
  根据变量的生效范围等标准:
  本地变量:生效范围为当前shell进程;对当前shell之外的其它shell进程,包括当前shell的子shell进程均无效
  环境变量:生效范围为当前shell进程及其子进程
  局部变量:生效范围为当前shell进程中某代码片断(通常指函数)
  位置变量:$1, $2, ...来表示,用于在脚本代码中调用通过命令行传递给它的参数。
  特殊变量:$?, $0, $*, $@,$#,$$

(3)本地变量
  变量赋值:name=‘value’
  可以使用引用value:
  (1) 可以是直接字串;name=“root"
  (2) 变量引用:name="$USER"
  (3) 命令引用:name=`COMMAND` name=$(COMMAND)
  变量引用:${name} $name
  "":弱引用,其中的变量引用会被替换为变量值
  '':强引用,其中的变量引用不会被替换为变量值,而保
  持原字符串
  显示已定义的所有变量:set
  删除变量:unset name
(4)环境变量
  变量声明、赋值:
  export name=VALUE
  declare -x name=VALUE
  变量引用:$name, ${name}
  显示所有环境变量:
  env
  printenv
  export
  declare -x
  删除变量:
  unset name
  bash内建的环境变量:
  PATH SHELLUSERUIDHOMEPWDSHLVL
  LANGMAILHOSTNAMEHISTSIZE —
(5)只读和位置变量
  只读变量:只能声明,但不能修改和删除
  声明只读变量:
  readonly name
  declare -r name
  查看只读变量:
  readonly -p
  位置变量:在脚本代码中调用通过命令行传递给脚本的参数
  $1, $2, ...:对应第1、第2等参数。$1表示第一个参数,$2表示第二个参数

  $0: 命令本身
  $#: 传递给脚本的参数的个数
  $*: 传递给脚本的所有参数,全部参数合为一个字符串
  $@: 传递给脚本的所有参数,每个参数为独立字符串
  $@和$* 只在被双引号包起来的时候才会有差异
  假设你的脚本运行时你写了三个参数 分别存储在$1 $2 $3中
  则"$*" 等价于 “$1 $2 $3 $4"---》传递了一个参数
  而“$@" 等价于 "$1""$2""$3""$4"   ---》传递了四个参数

  如图,分别使用两种方式将1 2 3 4传给aa.sh和bb.sh,然后取第一个参数,果然发现输出的结果表明$@传递了四个参数,因此取第一个才会是1。
  set -- 清空所有位置变量

  如图,使用set --后所有变量被清空
  PS:引用一位数以上的变量(如上图的$10)时要加{},不然系统会认为是$1和0。

(6)参数左移
  shift n 用于对参数的移动(左移)


  如图,参数向左移动了两位(就是删除最左边两个)。由abcdefg变成cdefg
3.退出状态
(1)退出状态
  进程使用退出状态来报告成功或失败
  0代表成功,1-255代表失败
  $? 变量保存最近的命令退出状态
  正常状态,$?值为0

  最后一条失败,$?值不为0
(2)自定义退出状态码
  exit :
  使用exit 也可以自定义退出状态码。注意:脚本中一旦遇到exit命令,脚本会立即终止;终止退出状态取决于exit命令后面的数字。
  注意:如果未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后一条命令的状态码。
4.算术运算
  bash中的算术运算:help let
  +, -, *, /, %取模(取余), **(乘方)
  实现算术运算:
  (1) let var=算术表达式
  (2) var=$[算术表达式]
  (3) var=$((算术表达式))
  (4) var=$(exprarg1 arg2 arg3 ...)
  (5) declare –i var = 数值
  (6) echo ‘算术表达式’ | bc
  乘法符号有些场景中需要转义。
  bash有内建的随机数生成器:$RANDOM(0-32767)
  echo$[$RANDOM%50] :0-49之间随机数
  (同理可以使用echo$[$RANDOM%50+1]随机产生1-50之间的随机数)
5.赋值
  增强型赋值:
  +=, -=, *=, /=,%=
  let varOPERvalue
  例如:let count+=3
  自加3后自赋值
  自增,自减:
  let var+=1
  let var++
  let var-=1
  let var--
6.逻辑运算
(1)与
  真与真真
  真与假假
  假与真假
  假与假假
  总结:只要有一个假则为假
  短路与:若前一个为假,则不再判断第二个值,因为结果必为假。
(2)或
  真或真 真
  真或假 真
  假或真 真
  假或假 假
  总结:只要有一个真则为真
  短路或:若前一个为真,则不再判断第二个值,因为结果必为真。
7.条件测试
  判断某需求是否满足,需要由测试机制来实现。专用的测试表达式需要由测试命令辅助完成测试过程。
  评估布尔声明,以便用在条件性执行中
  若真,则返回0
  若假,则返回1
  测试命令:
  test EXPRESSION
  [ EXPRESSION ]
  ` EXPRESSION `
  注意:EXPRESSION前后必须有空白字符

  根据退出状态而定,命令可以有条件地运行
  && 代表条件性的AND THEN
  ||代表条件性的OR ELSE
  就是说如果前一条命令输出为0,就执行&&后面的内容,否则执行||后面的内容。
  使用这种方法就不用每次使用$?调取结果了

  另外,使用[]可以判断是否有值,如有则输出0,如没有则输出1


8.bash的测试
(1)数值测试
  -gt 是否大于
  -ge 是否大于等于
  -eq 是否等于
  -ne 是否不等于
  -lt 是否小于
  -le 是否小于等于

(2)字符串测试
  == 是否等于
  >ascii码是否大于ascii码
  <是否小于
  != 是否不等于
  =~ 左侧字符串是否能够被右侧的PATTERN所匹配(部分内容被匹配即可)
  注意: 此表达式一般用于` `中;扩展的正则表达式

  -z "STRING“ 字符串是否为空,空为真,不空为假
  -n "STRING“ 字符串是否不空,不空为真,空为假
  注意:用于字符串比较时的用到的操作数都应该使用引号
(3)文件测试
  使用方式为选项加文件:-x FILE
  存在性测试:
  -a 判断文件存在则为真
  -e 同-a

  存在性及类别测试:
  -b 判断文件为块设备文件则为真
  -c 判断文件为字符文件则为真
  -d 判断文件为目录文件则为真
  -f 判断文件为普通文件则为真

  -h 判断文件为软链接文件则为真
  -L 同-h

  -p 是否存在且为命名管道文件
  -S 是否存在且为套接字文件
  文件权限测试:
  -r 判断当前用户对该文件可读时为真(root永远为真)
  -w 判断当前用户对该文件可写时为真(root永远为真)
  -x 判断当前用户对该文件可执行为真(只要有任意位置有x,root则为真)
  文件特殊权限测试:
  -u 判断该文件有suid权限为真(对于非二进制文件加上suid即使为真也无效)
  -g 判断该文件有sgid权限为真(对于非二进制文件加上sgid即使为真也无效,目录有效)
  -k 判断文件是否有sticky权限(对于普通文件没有意义)
  文件大小测试:
  -s 判断文件(非目录)为非空时为真
  文件是否打开:
  -N 判断文件在上一次读取后被改过则为真。
  -O 判断文件的owner为当前用户时为真
  -G 判断文件的group是当前用户的主组时为真
  双文件测试:
  使用方式为FILE1 -ef FILE2
  -ef 判断两个文件是硬链接时为真

  -nt 判断前一个文件的mtime新于后一个文件时为真
  -ot 判断前一个文件的mtime旧于后一个文件时为真
(4)组合测试条件
  第一种方式:
  COMMAND1 && COMMAND2 并且
  COMMAND1 || COMMAND2 或者
  ! COMMAND非
  如:` -r FILE `&&` -w FILE `
  第二种方式:
  EXPRESSION1 -a EXPRESSION2 并且
  EXPRESSION1 -o EXPRESSION2 或者
  ! EXPRESSION
  必须使用测试命令进行

9.接受输入
  使用read来把输入值分配给一个或多个shell变量
  -p 指定要显示的提示

  read -p “Enter a filename: “ FILE

  -s 静默输入,一般用于密码

  (注意,必须是sp如果一起使用必须是-sp,不能用-ps)
  -n N 指定输入的字符长度N

  -d ‘字符’输入结束符(就是当输入指定结束符时就算输入结束,会自动跳到下一行)
  -t N TIMEOUT为N秒 (给用户的输入做限时规定。若超出-t参数后所规定的时间值后,脚本将终止用户的输入,可单独使用也可和其它参数配合连用。)
  read 也可以从标准输入中读取值,给每个单词分配一个变量(注意:不支持管道)。如果变量数少于单词数,则所有剩余单词都被分配给最后一个变量
  read 变量名1 [变量名2] < 文件名

  也可以使用 /etc/profile.d/*.sh
  总结:非交互式登陆下,bash自身只读取~/.bashrc 文件,然后文件中调用/etc/bashrc文件中又继续调用/etc/profile.d/*.sh
  ※举个具体例子加深理解吧:

  如图,我们分别在这5个文件中加上5段定义变量的话。此时查看5个变量的值,发现为空。因为此时并没有重新登录所以这些文件不重新读取。

  于是我们退出并重新登陆。
  此时可以看到,分别有定义的值了。

  然后我们将C3改成C6

  (改完之后目前还是原来的结果,因为没有重新登录)
  然后我们使用非交互式登陆root
  注意:非交互式登陆有一个特点,它不是登陆一个新的环境,会继承之前shell的所有变量,当然了,如果重新赋值了,它当然会被重新覆盖掉。

  因此我们发现变量的值仍然不变。因为即使修改了C,但是非登录shell并不读取~/.bash_profile文件,所以不会被重新赋值。
  然后我们退出这个shell到之前的shell,将/etc/bashrc中的E5改为E7。

  因为从来都没有重新读取过,因此此时读取变量的话,仍然是12345这5个值。
  然后再非交互式登陆到root下,

  发现E的值改变了,因为非交互式登陆是需要读取/etc/bashrc文件的。
  然后我们再退出到上一个shell,将B2改成B8

  此时读取变量仍然是12345,

  然后使用非交互式登陆到liubei用户下,发现B的值也改变了。因为非交互式登陆也需要读取/etc/profile.d/*.sh文件的。
  然后我们再退出,将D4改为D9

  发现变量仍然为

  因为我们改的是root下的.bashrc文件,而liubei用户读取的应该是自己家目录的.bashrc文件,因此D的值不变。
  然后我们退出并使用交互式登陆liubei用户
  此时变量为:

  因为交互式登录不会继承之前shell的内容而是全部重新读取,而liubei用户又只会读自己家目录下的.bash_profile文件,而不会读取root下的.bash_profile文件,因此C的值为空。同理,也不会读D的值。因此这两个变量均为空。
  PS:修改文件后需生效有两种方法:
  1 重新启动shell进程(像刚才举例子中的方式)
  2 使用. 或source例如:. ~/.bashrc
13. $-变量
  h:hashall,打开这个选项后,Shell 会将命令所在的路径hash下来,避免每次都要查询。通过set +h将h选项关闭
  i:interactive-comments,包含这个选项说明当前的shell 是一个交互式的 shell。所谓的交互式shell,在脚本中,i选项是关闭的。
  m:monitor,打开监控模式,就可以通过Job control来控制进程的停止、继续,后台或者前台执行等。
  B:braceexpand,大括号扩展
  H:history,H选项打开,可以展开历史列表中的命令,可以通过!感叹号来完成,例如“!!”返回上最近的一个历史命令,“!n”返回第 n 个历史命令

  正常查询时全部开启,某些变量可以通过命令开启或关闭

  如图,关闭h选项。

页: [1]
查看完整版本: Shell脚本编程基础——Linux基本命令(11)