hhnf333 发表于 2018-8-20 10:06:39

第七章,shell编程基础

  更多笔记点击查看
  Linux学习从入门到打死也不放弃,完全笔记整理(持续更新)
  http://blog.51cto.com/13683480/2095439
  笔记整理开始时间:2018年4月12日11:37:35
  本章内容:
  编程基础
  脚本基本格式
  变量
  运算
  条件测试
  配置用户环境
  编程基础:
  程序:指令+数据
  程序编程风格:
  过程式:以指令为中心,数据服务于指令
  面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤
  一步一步实现,使用的时候一个一个依次调用就可以了
  对象式:以数据为中心,指令服务于数据
  面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为
  了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为
  shell程序:提供了编程能力,解释执行
  是对一堆Linux命令的逻辑化处理
  程序的的执行方法:
  计算机:运行二进制指令
  编程语言:
  低级:汇编
  高级:
  编译:高级语言-->编译器-->目标代码
  在编译时将代码转换成2进制
  java,c#
  解释:高级语言-->解释器-->机器代码
  在程序执行时才转换成2进制
  shell,perl,python
  编程基本概念:
  编程逻辑处理方式
  顺序执行,循环执行,选择执行
  shell编程:过程式,解释执行
  编程语言的基本结构:
  各种系统命令的组合
  数据存储:变量、数组
  表达式:a + b
  语句:if
  shell脚本基础:
  shell脚本:
  包含一些命令或声明,并符合一定格式的文本文件
  格式要求:首行shebang机制
  #!/bin/bash                        shell
  #!/usr/bin/python      python
  #!/usr/bin/perl                  perl
  shell脚本的用途有:
  自动化常用命令
  执行系统管理和故障排除
  创建简单的应用程序
  处理文本或文件
  创建shell脚本:
  第一步:使用文本编辑器来创建文本文件
  第一行必须包括shell声明序列:#!
  #!/bin/bash
  添加注释
  注释以#开头
  第二步:运行脚本
  给予执行权限,+x,在命令行上指定脚本的绝对或相对路径
  /root/hello
  直接运行解释器(bash),如:
  bash/root/hello
  cat ff115|bash
  PS:source 执行程序表示脚本会在当前shell运行不开启子进程
  脚本规范:
  1.第一行一般为调用使用的语言
  2.程序名,避免更改文件名为无法,正确找到的文件
  (如不要取名bash,或者其他存在的程序名)
  3.版本号
  4.更改后的时间
  5.作者相关信息
  6.该程序的作用。以及注意事项
  7.最后是各版本的更新简要说明
  脚本基本结构
  #!shebang
  configuration_variables      配置变量
  function_definitions            定义函数
  main code                                  主要代码
  脚本调试:
  检测脚本中的语法错误
  bash -n hello.world
  如:
  #bash -n ceshi
  ceshi: line 2: unexpectedEOF while looking for matching `"'
  ceshi: line 7: syntaxerror: unexpected end of file
  调试执行:
  bash -x hello.world
  PS:
  bash -n 只检查语法错误
  如果是语法错误后续命令不执行
  如果是命令not found 后续会继续执行
  bash -x+代表深度,直接执行+,被调用执行++
  脚本内不支持别名,也无法添加别名
  变量:命名的内存空间
  数据存储方式:
  把程序中准备使用的数据赋给一个简短、易于记忆的名字
  类型:
  字符型
  数值:×××,浮点型
  作用:
  数据存储
  参与运算
  表示数据范围
  强类型:
  变量不经过强制转换,它永远是这个数据类型,不允许隐式的类型转化。一般
  定义变量时必须指定类型,参与运算必须符合类型要求;调用未声明变量会
  产生错误。
  如jave c#
  弱类型:
  语言的运行时会隐式做数据类型转换。无须指定类型,默认均为字符型,参
  与运算会自动进行隐式类型转换,变量无须事先定义可直接调用
  如:bash不支持浮点数, php
  变量命名法则:
  1.不能使用程序中的保留字;例如:if ,for
  2.只能使用数字、字母及下划线,且不能以数字开头
  3.见名知义
  4.统一命名规则:驼峰命名法
  bash中变量的种类:
  根据变量的生效范围等标准等标准划分下面变量类型:
  局部变量:
  生效范围为当前shell进程;对当前shell之外的其他shell进程,
  包括当前shell的子shell进程均无效
  环境(全局)变量:
  生效范围为当前shell进程及其子进程
  本地变量:生效范围为当前shell进程中某代码片段,通常指函数
  位置变量:$1,$2,..${10}..来表示,用于让脚本在脚本代码中调用通过命令行传递
  给它的参数
  特殊变量:
  $?,$0,$*,$@,$#,$$
  $?         前一个命令的退出状态,成功为0,不成功为非0
  局部变量:
  变量赋值:name='value'
  可以使用引用value:
  1.可以是直接字串;   name=‘root’
  2.变量引用:         name=$USER
  3.命令引用:         name=`command`
  name=$(cmd)
  ps:
  变量一旦赋值,除非重新赋值,否则所占内存空间不变,值不变
  name1=name2的情况
  就算赋值之后name2的值改变了,name1的值保持不变
  i=100      赋值为字符,不问数字类型
  变量引用:
  ${name}$name
  "":弱引用,其中的变量引用会被替换为变量值,如
  #echo "$PS1"
  \[\e[\u@\h \w]\$\[\e
  '':强引用,其中的变量引用不会被替换为变量值,而保持原字符串
  #echo '$PS1'
  $PS1
  显示已经定义的所有变量:set
  删除变量:   unset name
  PS:
  pstree -p      进程tree
  echo $$当前进程的进程编号
  echo $PPID 父进程的进程编号
  练习1
      1、编写脚本/root/bin/systeminfo.sh,显示当前主机系统信息,包括主机名,
  IPv4地址,操作系统版本,内核版本,CPU型号,内存大小,硬盘大小
      2、编写脚本/root/bin/backup.sh,可实现每日将/etc/目录备份到
  /root/etcYYYY-mm-dd中
      3、编写脚本/root/bin/disk.sh,显示当前硬盘分区中空间利用率最大的值
      4、编写脚本/root/bin/links.sh,显示正连接本主机的每个远程主机的IPv4地址
  和连接数,并按连接数从大到小排序
  环境变量:
  变量声明,赋值:
  export name=Value             相当于name=Value;exportname
  declare -x name2=Value
  letc=name+name2;export c
  变量引用:$name,${name2}
  显示所有环境变量:
  env
  printenv
  export
  declare -x
  删除变量:
  unset name
  bash内建的环境变量:
  PATH:
  SHELL:
  USER:
  UID:
  HOME:
  PWD:
  SHLVL:          当前shell层数
  LANG:            语言键盘、字符编码
  MAIL:         当前用户mail目录
  HOSTNAME:
  HISTSIZE:
  _:                  前一个命令的最后一个参数
  只读和位置变量:
  只读变量:只能声明,但不能修改和删除
  声明只读变量:
  readonlyname
  declare -rname
  查看只读变量:
  readonly-p
  位置变量:再脚本代码中调用通过命令行传递给脚本的参数
  $1,$2,..${10}..:   对应相应第1,2..10..个参数
  脚本中命令:shift 可以传递参数位置,如:
  shift            可以将原本$2,变成$1
  shift 3            将原$4变成$1
  $0    命令本身,名字
  默认带路径,可以用 `basename $0`取出来
  $0如果是软链接的话 $0会显示各自软链接的名字
  $*   传递给脚本的所有参数,全部参数合为一个字符串
  $@   传递给脚本的所有参数,每个参数为独立字符串
  $#   传递给脚本的参数的个数
  $@ $*    在脚本调用脚本传递参数时,如果用"$*",会将所有参数当成一个
  字符串传递
  $* $@"$@"   会将每个参数单独传递
  set --   清空所有位置变量
  退出状态
  进程使用退出状态来报告成功或失败
  $?            保存最近的命令退出状态
  0            成功
  1-255   失败
  例如:
  ping -c1 172.20.3.14 &>/dev/null
  echo $?
  退出状态码:
  bash 自定义退出状态码
  exit     自定义退出状态码
  注意:
  脚本中一旦遇到exit命令,脚本会立即终止;终止退出状态取决于
  exit命令后面的数字
  如果没有给脚本指定退出状态码,整个脚本的退出状态码取决于脚本
  中执行的最后一条命令的状态码
  算术运算:let
  bash中的算术运算:help let
  常用算术:
  +,-,*,/,%(取模 取余),**(乘方),id++,id--,
  实现算术运算的格式:
  1.   let var=算术表达式
  letz=x+y;let x++;lety=x**2;
  letz=(3*x+4*y/3)-2*x
  2.   var=$[算术表达式]
  z=$[(3*x+4*y/3)-2*x]
  3.   var=$((算术表达式))
  z=$(((3*x+4*y/3)-2*x))
  4.   var=$(expr arg1 arg2arg3...)
  如:z=$(expr $x + $y)         表示z=x+y
  *需要写成\*
  5.   declare -ivar=数值(可以使是算式)
  declare -ix=x+y
  declare -ix=3*x+y*4/2
  6.   echo ’算术表达式‘ |bc
  bash有内建的随即数生成器:$RANDOM(0-32676)
  echo $[$RANDOM%50]:               0-49之间随机数
  赋值:
  增强型赋值:
  +=,-=,*=,/=,%=
  let x+=3;x-=1;x*=5;x/=4
  +3 -1*5   /4
  shell不支持浮点计算,所以除法会有商整取余
  自增,自减
  let x+=1;let x++
  let x-=1;let x--
  练习2
  1、编写脚本/root/bin/sumid.sh,计算/etc/passwd文件中的第10个用户和第
  20用户的ID之和
     2、编写脚本/root/bin/sumspace.sh,传递两个文件路径作为参数给脚本,计
  算这两个文件中所有空白行之和
     3、编写脚本/root/bin/sumfile.sh,统计/etc, /var, /usr目录中共有多少个一级
  子目录和文件
  逻辑运算
  与:      &
  或:      |
  非:      !
  !1=0
  !0=1
  短路运算:
  cmd1 && cmd2
  如果cmd1为假,cmd2不需要执行,反之cmd1为真,需要cmd2执行
  cmd1 || cmd2
  如果cmd1为真,cmd2不需要执行,反之cmd1为假,需要cmd2执行
  cmd1 && cmd2 || cmd3    要求cmd2必真
  cmd1为真,执行cmd2
  为假,执行cmd3
  异或:^ XOR
  二进制运算,同为0 异为1
  a=5;b=6;echo $a$b;a=$;b=$;a=$;echo $a $b
  将ab的值互换
  ture 和false
  只返回真或者假,不做任何操作
  true && echo hello
  false   && echo hello||echo nihao
  条件测试:test
  判断某需求是否满足,需要由测试机制来实现
  专用的测试表达式需要由测试命令辅助完成测试过程
  评估布尔声明,以便用在条件性执行中
  若真      则返回0
  若假      则返回1
  测试命令:
  test expression            如:test a = b ;echo$?
  [ $a = b ] && echo ture || echofalse
  [[ $a =~ pattern ]]
  表达式epression 前后必须有空白字符
  根据退出状态而定,命令可以有条件的执行
  && 代表条件性的and then
  ||      代表条件性的 or else
  例如:
  grep -q no_such_user /etc/passwd || echo 'NO suchuser'
  id usera &>/dev/null && echo "usera is exist" || useraddusera
  长格式的例子:
  test "$A" == "$B" && echo "Strings areequal"
  [ "$A" == "$B" ]
  test "$A" -eq "$B" && echo "Integers areequal"
  [ "$A" -eq "$B" ]
  bash的数值测试:
  -v var
  变量是否设置 test -v var && echo hello||echonihao
  [ -v var ] && set || notset
  PS:
  此处使用变量var前不可加"$",否则判断异常
  数值测试:
  -gt 是否大于            [ $A -gt $B]
  -ge      是否大于等于
  -eq         是否等于
  -ne      是否不等于
  -lt         是否小于
  -le          是否小于等于
  bash的字符串测试:
  ==          是否等于                                    等于为真,0
  >            ascii码是否大于ascii码
  <                           是否小于
  !=            是否不等于                                 不等于为真,0
  =~         左侧字符串是否能够被右侧的pattern所匹配
  注意:此表达式一般用于[[ ]]中,支持扩展的正则表达式
  -z &quot;string&quot;            字符串是否为空,空为真,不空为假
  -n &quot;string&quot;             字符串是否不空,不空为真,空为假
  注意:   用于字符串比较时用到的操作数都应该使用引号
  [[ ]]使用pattern时 表达式 不能加引号 ,也不能识别\< \>\b
  判断是否为空也可以:
  [ x = x&quot;$a&quot; ] && echo ture || echo false
  练习3:
  1、编写脚本/root/bin/argsnum.sh,接受一个文件路径作为参数;如果参数
  个数小于1,则提示用户“至少应该给一个参数”,并立即退出;如果参数个数
  不小于1,则显示第一个参数所指向的文件中的空白行数
   2、编写脚本/root/bin/hostping.sh,接受一个主机的IPv4地址做为参数,测
  试是否可连通。如果能ping通,则提示用户“该IP地址可访问”;如果不可
  ping通,则提示用户“该IP地址不可访问”
   3、编写脚本/root/bin/checkdisk.sh,检查磁盘分区空间和inode使用率,如
  果超过80%,就发广播警告空间将满
  Bash的文件测试:
  存在性测试:
  -a file            同-e
  -e file             文件存在性测试,存在为真,否则为假
  存在性及类别测试
  -b file             是否存在且为块设备文件
  -c file            是否存在且为字符设备文件
  -d file             是否存在且为目录文件
  -f file            是否存在且为普通文件
  -h file   或 -L file      是否存在且为符号链接文件
  -p file    是否存在且为命名管道文件
  -S file             是否存在且为套接字文件
  Bash的文件权限测试:
  文件权限测试:
  -r file            是否存在且可读
  -w file             是否存在且可写
  -x file   是否存在且可执行
  文件特殊权限测试:
  -u file             是否存在且拥有suid权限
  -g file             是否存在且拥有sgid权限
  -k file   是否存在且拥有sticky权限
  Bash的文件属性测试:
  文件大小测试:
  -s file            是否存在且为空
  文件是否打开
  -t fd:fd 文件描述符是否在某终端已经打开
  -N file             文件自从上一次被读取之后是否被修改过
  -O file             当前用户是否为文件属主
  -G file             当前有效用户是否为文件属组
  双目测试:
  file1 -ef file2          file1是否是file2的硬链接
  file1 -nt file2 file1是否新于file2(mtime)
  file1 -ot file2         file1是否旧与file2
  Bash的组合测试条件:
  第一种方式:
  cmd1 && cmd2    且
  cmd1 ||   cmd2      或
  !cmd                  非
  如:       [[-r FILE ]] && [[ -w FILE]]
  第二种方式:
  [ expression1 -a expression2 ]            并且
  [ expression1 -o expression2 ]            或者
  [ !expression ]                              非
  例:
  [ -z &quot;$HOSTNAME&quot; -o &quot;$HOSTNAME&quot; == &quot;localhost.localdomain&quot; ] &&
  hostname www.magedu.com
  [ -f /bin/cat -a -x /bin/cat ] && cat/etc/fstab
  PS:
  &&(-a)   ||(-o)可连续使用
  [ -r &quot;$1&quot; -a -w &quot;$1&quot; -a -x &quot;$1&quot; ]&& echo ture ||false
  [ -a &quot;$1&quot;] && [ -r &quot;$1&quot; ] && [ -w &quot;$1&quot; ] && [ -x &quot;$1&quot; ]&& echo ture || false
  只要有一个为假,就返回假
  [ -r &quot;$1&quot; -o -w &quot;$1” -o &quot;$1&quot; ] && echoture || false
  [ -r &quot;$1&quot;] || [ -w &quot;$1&quot; ] || [ -x &quot;$1&quot;] && echo ture ||false
  只要一个为真,则返回为真
  练习:
  1、编写脚本/bin/per.sh,判断当前用户对指定参数文件,是否不可读并且不可写
      2、编写脚本/root/bin/excute.sh ,判断参数文件是否为sh后缀的普通文件,如
  果是,添加所有人可执行权限,否则提示用户非脚本文件
      3、编写脚本/root/bin/nologin.sh和login.sh,实现禁止和充许普通用户登录系统
  read:
  使用read来把输入值分配给一个或多个shell变量
  -p                  指定要显示的提示,如:
  read -p&quot;Please input your name: &quot; name
  -s                  静默输入,一般用于密码,如:
  read -s -p&quot;Please input your password: &quot; passw
  -n N               指定输入的字符长度N
  指定长度之后,如达到长度,后续指令不会换行,直接在输入的内容之后显示了
  想要达到换行的目的,需要下一行加上
  echo&quot;&quot;   但是如果手动回车则会显示一行空行
  -d '字符' 输入结束符   到此字符直接结束输入

  read -t 20 -n20 -p &quot;Please input you>  与-n类似,也是不会换行
  -t N      TIMEOUT为N秒
  timeout并不会退出脚本,而是会执行后续指令
  read      如果从标准输入中读取值,给每个单词分配一个变量
  所有剩余单词都被分配给最后一个变量
  不支持管道接受标准输入   | read name
  bash如何展开命令行
  把命令行分成单个命令词
  展开别名
  展开大括号的声明({})
  展开波浪符声明(~)
  命令替换$()和(``)
  再次吧命令行分成命令词
  展开文件通配(*、?、等等)
  准备I/O重导向()
  运行命令
  防止扩展:
  反斜线 \ 会使随后的字符按原意解释
  $   echo your cost:\$5.00
  your cost:$5.00
  加引号来防止扩展
  单引号''   防止所有扩展
  双引号&quot;&quot; 也防止所有扩展,但是以下情况例外
  $                   --变量扩展
  `` $()      --命令替换
  \                  --禁止单个字符扩展
  !                   --历史命令替换
  bash的配置文件:
  按生效范围划分、存在两类
  全局配置:
  /etc/profile
  /etc/profile.d/*.sh
  /etc/bashrc
  个人配置:
  ~/.bash_profile
  ~/.bashrc
  shell登录两种方式
  交互式登录:
  1)直接通过终端输入账号密码登录
  2)使用 su - username 切换的用户
  执行顺序:
  /etc/profile -->/etc/profile.d/*.sh --> ~/.bash_profile -->
  ~/.bashrc -->/etc/bashrc
  非交互式登录:
  1)su username
  2)图形界面下打开的终端
  3)执行脚本
  4)任何其他的bash实例
  执行顺序:~/.bashrc -->/etc/bashrc --> /etc/profile.d/*.sh
  按功能划分:
  profile类:
  为交互式登录的shell提供配置
  全局:/etc/profile,/etc/profile.d/*.sh
  个人:~/.bash_profile
  功能:
  用于定义环境变量
  运行命令或脚本
  bashrc类:
  为交互式和非交互式登录的shell提供配置
  全局:/etc/bashrc
  个人:~/.bashrc
  功能:
  定义命令别名和函数
  定义本地变量
  配置文件修改生效:
  修改profile和bashrc文件后需生效
  两种方法:
  重新启动shell进程(重新登录)
  . 或source
  例如:. ~/.bashrc
  Bash退出任务:
  保存在~/.bash_logout文件中
  在退出登录shell时运行
  用于:
  创建自动备份
  清楚临时文件
  变量:$-
  h:hashall,打开这个选项后,shell
  会将命令所在的路径hash下来,避免每次都要查询。通过set+h将h选项关闭
  i:interactive-comments,包含这个选项说明当前的shell是一个交互式的shell
  所谓的交互式shell,在脚本中,i选项都是关闭的
  m:monitor,打开监控模式,就可以通过jobcontrol来控制进程的停止、继续、
  后台或者前台执行等。
  B:braceexpand,大括号扩展
  H:history,H选项打开,可以展开历史列表中的命令,可以通过!来完成,
  例如!!,返回最近的一个历史命令,!n返回第n个历史命令
  练习:
  1、让所有用户的PATH环境变量的值多出一个路径,例如:
  /usr/local/apache/bin
      2、用户root登录时,将命令指示符变成红色,并自动启用如下别名:
  rm=‘rm –i’
  cdnet=‘cd/etc/sysconfig/network-scripts/’
  editnet=‘vim/etc/sysconfig/network-scripts/ifcfg-eth0’
  editnet=‘vim /etc/sysconfig/network-scripts/ifcfg-eno16777736或 ifcfg-ens33 ’ (如果系
  统是CentOS7)
      3、任意用户登录系统时,显示红色字体的警示提醒信息“Hi,dangerous!”
      4、编写生成脚本基本格式的脚本,包括作者,联系方式,版本,时间,描述等
      5、编写用户的环境初始化脚本reset.sh,包括别名,登录提示符,vim的设置,
  环境变量等
  笔记整理完成时间:2018年4月13日16:58:39

页: [1]
查看完整版本: 第七章,shell编程基础