scaoping 发表于 2018-8-20 12:58:01

九、shell编程

  变量初始化:在变量声明的时候给变量一个初始值,初始化相当于给里面放东西。
  变量赋值:手动给变量空间中存储数据的过程。
  变量类型转换:显式、隐式,比如讲字符型转换成数值型。
  变量类型:
  本地变量:
  set var_name=value
  unset var_name
  ${var_name}
  作用范围:当前shell进程。
  局部变量:
  local var_name=value
  unset var_name
  ${var_name}
  作用范围:当前shell进程的局部范围内有效
  环境变量:
  export var_name=value
  unse var_name
  ${var_name}
  作用范围:当前shell及其子shell。
  位置变量:$1/$2................
  特殊变量:$$/$?/$#/$@...................
  脚本的写法格式:
  指定脚本运行的shell环境:
  独立执行脚本的条件:
  1、要有执行权限。
  2、定义好shebang,及脚本的第一行:#! /path/to/explainer 例如:/bin/bash ,/usr/bin/python。
  3、定义命令的path环境变量。
  bash的配置文件:
  profile:声明环境变量,执行程序脚本 ,/etc/profile,/etc/profile.d/*.sh,~/bash_profile,交互式登陆
  bashrc:定义本地变量、定义命令别名/etc/bashrc,~/.bashrc,非交互式
  脚本文件中,除第一行外其他所有已#开头的行均为注释行。
  练习一、添加一组用户,并且用户名同密码一样。
  #!/bin/bash
  #author:gongbing
  #time :20150731
  #version:1.0
  #description:add user
  useradd user1
  echo user1 |passwd --stdin user1&>/dev/null
  echo "add user1 successful!"
  useradd user2
  echo user2 |passwd --stdin user2 >/dev/null
  echo "add user1 successful!"
  useradd user3
  echo user3 |passwd --stdin user3 >/dev/null
  echo "add user1 successful!"
  编写完毕保存为.sh文件,并赋予执行权限。
  检查脚本的语法错误:
  bash -n 脚本路径/脚本名
  调试执行脚本语法:
  bash -x /path/to/script_file.sh
  变量名称取名规则:
  1、数字、字母、下划线
  2、不能以数字开头
  3、区分大小写
  4、风格统一,见名知意。
  面向过程的编译语言,都有语言控制结构:
  1、顺序执行:默认、逐条执行。
  2、选择执行:依据条件语句判断来选择执行的步骤。 0:真,非零:假
  3、循环执行:依据条件重复执行某一条命令的次数。
  控制语句:
  不同语句写在同一行里需要用分号;隔开。
  bash循环控制语句:
  for循环:
  事先提供一个元素列表,然后让变量去遍历(挨个提取)此元素列表;每访问一个元素,执行一次循环体,直至元素遍历完毕。
  用法: for var_name in 元素列表比如元素1 元素2 元素3
  do
  语句1;
  语句2;
  done
  while
  until
  练习二:给练习一调整为循环语句。
  #!/bin/bash
  for username in user1 user2 user3;
  do;
  useradd $username ;
  echo $username |passwd --stdin $username;
  done;
  练习三 、显示/et/inittab,/etc/rc.d/rc.sysinit,/etc/fstab三个文件各有多少行。
  #!/bin/bash
  for PathWc in /etc/inittab /etc/rc.d/rc.sysinit /etc/fstab
  do
  cat $PathWc |wc -l
  done
  练习:
  1、 使用for循环创建/tmp/1.dir,/tmp/2.dir和/tmp/3.dir,权限为750
  #!/bin/bash
  for Direc_Gest in 1.dir 2.dir 3.dir
  do
  mkdir /tmp$Dire_Gest
  chmod 750 /tmp/$Dire_Gest
  done
  2、统计/etc/fstab、/etc/rc.d/rc.sysinit、/etc/inittab文件中各自以#开头的行的行数和空白行行数。
  #!/bin/bash
  for filecount in /etc/fstab /etc/rc.d/rc.sysinit /etc/inttab
  do
  egrep ^#|^$ $filecount |wc -l
  done
  3、将/etc/passwd 、/etc/shadow的最近一次修改时间改为2010年3月12日14:11 3秒
  #!/bin/bash
  for ModfyTime in/etc/passwd /etc/shadow
  do
  touch -m -t 201003121411.03 $ModfyTime
  #touch -a 修改访问时间 默认当前时间
  #touch -m 修改修改时间 当前时间
  #touch -m -t yymmddhhmm.ss 修改指定时间。
  done
  4、将user1、user2、user3加入到testgrp组中,以其为额外组。
  #!/bin/bash
  groupadd testgrp
  for usertogrp in 1 2 3
  do
  usermod -G testgrp user$usertogrp
  done
  5、copy /etc/passwd /etc/shadow /etc/inittab 到/tmp/目录下,并将名称已当前时间进行重命名。
  #!/bin/bash
  for filerename in/etc/passwd /etc/shadow /etc/inittab
  do
  basefile= `basename $filerename`
  cp $filename /tmp/$basefile-`date +%F`
  done
  6、显示/etc/paswd文件的第1、3、6、12个用户的用户名、id、基本组的组名。
  #!/bin/bash
  for Line in 1 3 6 12
  do
  username=`head -n 1 /etc/passwd |tail -n 1 |cut -d : -f 1`
  Idname=`head -n 1 /etc/passwd |tail -n 1 |cut -d : -f 3`
  Groupname='id -gn $username'

  echo "username:$username>  done
  列表的生成:
  1、逐个列出,例如1 2 3 4
  2、使用通配符列出,例如 /etc/*
  #!/bin/bash
  for file in /etc/*
  do
  file $file
  done
  3、使用命令生成列表。
  #!/bin/bash
  for File in `ls/var`
  do
  file /var/$File
  done
  4、生成数字序列,
  {}:例如生成1到100的数值,{1..100}
  equ:equ [起始数字] [步长] [结束数字]
  练习:
  1、取出每个用户的用户名和shell
  思路:首先需要确定行数
  #!/bin/bash
  line=`wc -l /etc/passwd |cut -d : f 1`
  for Line in equ 1 $line
  do
  head -$Line /etc/passwd |tail -1 |cut -d: -f 1,7
  done
  如何在shell中进行算术运算
  shell不支持浮点数(小数),计算结果中如果有浮点数会被圆整为正数(化零为整)
  默认变量使用的是字符变量类型。实现算数运算的方法:
  1、   $[变量名]=valume
  2、   $((变量名))=valume
  3、 let   例如:let a=$a+$b
  4、 expr例如:f=`expr $a + $b`
  练习:
  随意声明两个变量,并给出整数值,然后计算他们的加减乘除的结果。
  #!/bin/bash
  Valume1=12
  Valume2=43
  for suanfa   in + - * /
  do
  echo "$Valume1$suanfa$Valume2= `let $Valume$suanfa$Valume`"
  done
  选择执行语句
  可以独自执行的命令不需要添加[]来完成测试。
  bash条件测试方式有以下几种:
  1、    [ expression ]:[]里面有空格。表示条件选择的依据。
  2、    ` expression `:
  3、    testexpression:
  4、    bash 命令:
  bash执行命令后有执行结果的状态返回值:echo $? (0表示成功,其他都是错误)
  可以使用exit命令在脚本中自定义脚本执行状态返回值,如果没有定义,脚本执行状态返回值取决于脚本执行结束前的最后一条语句的执行结果。
  判断格式:
  单分支if语句:
  1、 if 条件 ;then
  语句1
  语句2
  fi
  练习:
  1、查看某用户是否存在,并显示相关信息。
  #!/bin/bash
  Username=user1

  if>  then
  echo "$Username is living"
  fi
  2、如果用户存在,显示用户id和shell信息。
  3、如果一个设备已经挂载,显示挂载点。
  4、检查某一文件的 的空白行,并统计行数。
  2、if 条件
  then
  语句1
  语句2
  else
  语句1
  语句2
  fi
  练习:
  1、检查用户是否存在,并显示相关信息,如果不存在创建用户名,密码。
  #!/bin/bash
  Username=zhangliang

  if>  then
  echo "$Username is living"

  echo "$Username>  else
  useradd $Username
  echo "no this username,please wait....useradding......   "
  echo "$Username" |passwd --stdin $Username

  echo "$Username>  fi
  整数测试:
  expression: 数值1 比较符号 数值2
  比较符号:
  -gt:大于号
  -ge:大于或等于号
  -eq:等于号
  -lt:小于号
  -le:小于或等于
  -ne:不等于
  例如,写一个脚本,随意生成两个整数,比较其大小,显示大数。
  #!/bin/bash
a=$RANDOMb=$RANDOMif [$a -gt $b ]then echo "the max number is $a"elseecho "the max number is $b"fi  2、给定一个整数,判定奇偶性。
  3、给定一个用户,如果其ID号大于499,就显示其为普通用户,否则显示其为管理员。
  4、给定一个用户,如果其uid等于gid,就说明这个是“good guy”否则显示“bad guy”
#!/bin/bashUsername=pulseif [ `id -u $Username` -eq `id -g $Username` ]thenecho "this user($Username) is good guy! "else  echo "this user($Username) is bad guy!"
  嵌套练习:
  求200以内的所有为3的整数倍的整数之和
#!/bin/bashsum=0for n in {1..100}doif [ $[$n%3] -eq 0 ]   then   sum=$[$sum+$n]   fidoneecho "300 zhengshu he equal is $sum"  bash编程之位置变量
  $1.....$11.......:表示可以通过执行程序,然后加常量的方式来执行并替换程序中的$1等相关变量。
  $@:表示可以将多个常数按照一个字符串的形式显示出来
  $*:将多个常数分别以各自字符串的形式显示出来。
  $#:汇总常数的个数。
  $0:脚本名称。
  #!/bin/bash
  echo $1
  echo $2
  echo $@
  echo $*
  echo $#
  执行程序:./pos.sh a b c d e
  执行结果:a
  b
  a b c d e
  a b c d e
  5
  例:通过参数传递n个正整数给脚本,并求和。
#!/bin/bashNum=0Count=0for n in $@doCount=$[$Count+$n]doneecho "Count is $Count"  shift:对一组数进行重新定位第一个数。shift之前的数被踢掉。
  实现位置参数轮替。
  #!/bin/bash
  echo $1
  shift
  echo $1
  shift
  echo $1
  执行:./shift.sh a b c d
  结果:a
  b
  c
  练习:
  添加10个用户,需要先判断用户是否存在,如果不存在才添加,统计添加的用户数,并显示总的用户数。
#!/bin/bashcountaddu=0for n in `seq 1 10`doif [ `grep "user$n" /etc/passwd` &>/dev/null ]      then         echo "old user"       else       adduser user$n       countaddu=$[$countaddu+1]    fidoneecho "adduser count is $countaddu"echo "countuser is :`wc -l /etc/passwd`"  字符测试:
  文件测试:
  默认变量使用的是字符变量类型。实现算数运算的方法:
  1、   $[变量名]=valume
  2、   $((变量名))=valume
  3、 let   例如:let a=$a+$b
  4、 expr例如:f=`expr $a + $b`
  — +:对两个变量做加法。
  — -:对两个变量做减法。
  — *:对两个变量做乘法。
  — /:对两个变量做除法。
  — **:对两个变量做幂运算。
  — %:取模运算,第一个变量除以第二个变量求余数。
  — +=:加等于,在自身基础上加第二个变量。
  — -=:减等于,在第一个变量的基础上减去第二个变量。
  — *=:乘等于,在第一个变量的基础上乘以第二个变量。
  — /=:除等于,在第一个变量的基础上除以第二个变量。
  — %=:取模赋值,第一个变量对第二个变量取模运算,再赋值给第一个变量。
  (1)、在括号运算中((i=$j+$k))运算符号两边可以有空格也可以没有空格,但是expr运算i=`expr $j + $k`中运算符号两边必须要有空格!
  (2)、乘法运算符号是 \* ,而不是 * ;除法运算 / 表示整除,1/2=0。
  2、Let expressions执行一个或多个表达式。
  (1)、表达式中的变量前不必有$.
  (2)、如果表达式中包含了空格或其他特殊字符,则必须引起来。(let i=i+1中除了let后面有一个空格外,其他地方不能有一个空格!)
  例:let “I = I + 1” 或 let i=i+1
  bash脚本的知识点:
  条件测试方式:
  bash命令:
  [ expression ]
  test expression
  ` expression `
  条件测试的方法:
  整数测试:
  大于:-gt
  小于:-lt
  等于:-eq
  大于等于:-ge
  小于等于:-le
  不等于:-ne
  字符测试
  文件测试
  命令状态返回值:0 正确
  exit :脚本执行的最后一条命令的状态返回值,

  bash编程之位置变量
  $1.....$11.......:表示可以通过执行程序,然后加常量的方式来执行并替换程序中的$1等相关变量。
  $@:表示可以将多个常数按照一个字符串的形式显示出来
  $*:将多个常数分别以各自字符串的形式显示出来。
  $#:汇总常数的个数。
  $0:脚本名称。如果是带路径的$0 ,使用basename $0

  bash测试之文件测试
  方法:操作符文件路径
  -f:测试其是否是普通文件,即文件类型为-。
  -d:测试其是否为目录文件,文件类型d
  -e:测试文件是否存在,存在为真,否则为假。
  -r:测试文档对当前用户来说是否可读。
  -w:测试文件对当前用户是否可写。
  -x:测试文件是否对当前用户可执行。
  -s:测试文件内容是否为空,不空为真,否则为假。
  -l:测试文件是否是链接文件。
  练习:如果/tmp/test10文件不存在,就创建之:
  if [ ! -e /tmp/test10 ];
  then
  mkdir /tmp/test10
  fi
  短路操作:
  与运算:&& 全真则真 ,有假则假
  或运算:|| 有假则全假,有真则全真
  通过以上运算思路,可以确定如果一个运算的前半部分是真,对于与运算,就需要进行后面的运算才能知道结果是真还是假,如果是用或运算,则知道前面是假可以推断出后面是任何运算都为假,也就没有必要进行后面的运算。这个就是短路运算的思维。
  比如:
  1、mkdir /backup
  tar Jcf /backup/etc-`date +%f`.tar.xz /etc/*
  2、tar xf /backup/etc-2013-07-22.tar.xz -C /var/tmp/
  3、               #!/bin/bash
comdec=$1 if [ -z $comdec ];then    comdec=gzipfi[ -d /backup ] || mkdir /backupif[ $comdec == 'gzip' ];then    tar zcf /backup/etc-`date +%F-%H-%S`.tar.gz /etc/*    [ $? -eq 0 ] && echo "backup etc finished.(gzip)"elif [ $comdec == 'bzip2' ];then    tar jcf /backup/etc-`date +%F-%H-%S`.tar.bz2 /etc/*    [ $? -eq 0] && echo "backup etc finished.(bzip2)"elif [ $comdec == 'xz' ];then    tar Jcf /backup/etc-`date +%F-%H-%S`.tar.xz /etc/*    [ $? -eq 0 ] && echo "backup etc finished.(xz)"else    echo "usage: `basename $0` {}"    exit 6fi  bash编程之CASE语句:
case 变量引用(${}) in value1)  语句
  ;;
value2)  语句
  ;;
value3)  语句
  ;;
  *)
  语句
esac#!/bin/bashif [ -z $comdec ];then    comdec=gzipfi[ -d /backup ] || mkdir /backupcase$comdec ingzip)    tar zcf /backup/etc-`date +%F-%H-%S`.tar.gz /etc/*    Retval=$?    ;;bzip2)    tar jcf /backup/etc-`date +%F-%H-%S`.tar.bz2 /etc/*    Retval=$?    ;;xz)    tar Jcf /backup/etc-`date +%F-%H-%S`.tar.xz /etc/*    Retval=$?    ;;*)    echo "usage: `basename $0` {}"    exit 6  ;;
  esac
  [ $Retval -eq 0] && echo "backup etc finished.($comdec)"
  
  
交互式编程及实例:  read命令
  可以读取键盘输入数值到变量中
  例如:
  read a b
  2 5
  echo $a
  2
  1、echo -n 表示不换行,结合read一起使用。
  2、read -p “内容” value
  参数:
  -t :设置超时时间
  -p :设置输出说明的内容
  练习: 显示一下菜单内容
  m|M show memory
  d|Dshow disk
  q|Q quit
  2、如果用户选择了第一个选项,在显示内存信息
  如果选择2,显示磁盘挂载及使用情况
  选择3,退出,并显示退出
  其他任何信息,均说明错误。
#!/bin/bashecho "(m|M) SHOW MEMORY"echo "d|D show disk"echo "q|Q quit"echo -n"please input (m|d|q)" && read choicecase $choice inm|M)   free -m   ;;d|D)   df -lh   ;;q|Q)   echo "you are quit now"   exit0   ;;*)    echo "invalid input"    exit 5    ;;esac~        安全上下文
  用户执行访问某一个文件的时候,涉及到两个内容,第一就是使用的命令,第二就是被访问对象,那么他的安全权限就分别由这两个来决定,如果他没有命令执行权限,被访问对象无法执行,同样如果被访问对象没有访问权限,那么即使他有命令执行权限也是没有用的。
  通过passwd来理解特殊权限。
  s:suid,set uid,属主有s权限,意味着任何用户在执行此程序的时候,其进程的属主不在是发起人本身,而是这个程序的属主。
  chmod u+|- s/path/to/somefile
  可以通过大小写s来判断这个suid是原来就有的还是后来赋予的,
  s:原来有
  S:后来加
  s:sgid set gid,属组有s权限,意味着执行此程序时,其进程的属组不再是运行者所属的基本组,而是程序的属组。
  chmod g+|- s /path/to/somefile
  t:sticky,黏贴位,附加在other的权限上,表现为t,作用是只有文件所有者可以删除,其他用户不可以删除。
  chmod o+|- t /path/to/somefile
  chmod 3775/tmp/test
  练习:
  1、复制/bin/cat为/tmp/cat
  cp /bin/cat /tmp/cat
  2、复制/etc/rc.d/rc.sysinit为/tmp/hello
  cp /bin/rc.d/rc.sysinit /tmp/hello
  3、设定helllo文件的其它用户权限为无权限。
  chmod o-rwx /tmp/hello
  4、切换至普通用户,执行/tmp/cat,查看/tmp/hello,验证是否可查。
  /tmp/cat /tmp/hello   无权限
  5、以root用户身份设定/tmp/cat 具有suid权限,然后用普通用户,查看/tmp/cat,/tmp/hello,并验证。
  chmod u+s /tmp/cat
  /tmp/cat /tmp/hello    成功   如果反过来只修改hello的suid,是不会执行成功的。
  不同命令操作权限不同,结果也不同,总之要求编辑权限既要设置命令权限,也要设置文件权限最好。
  练习二:
  1、创建组magedu
  groupadd magedu
  2、添加用户hadoop和hive,均以magedu为额外组。
  useradd -g magedu hadoo
  3、创建目录/tmp/test,并设定其组为magedu。
  mkdir /tmp/test
  chgrp magedu /tmp/test
  4、分别使用两个普通用户在/tmp/test目录创建文件,看权限。
  su hadoo
  touch /tmp/test/123不成功
  5、设定/tmp/test目录具有写权限。
  chmod g+w /tmp/test
  6、再次分别使用普通用户创建文件,查看权限。如果能,查看文件属组
  touch /tmp/test/123 不成功
  7、设定/tmp/test的属组具有SGID,再次创建并查看。并验证删除操作
  chmod g+s /tmp/test/123 成功
  8、以root设定/tmp/test具有sticky,验证删除操作。
  rm /tmp/test/123 成功
  chmod o+t /tmp/test
  rm /tmp/test/123   不成功,权限不足。
  练习三:
  1、复制/etc/issue为/tmp/issue
  cp /etc/issue /tmp/issue
  2、修改/tmp/issue的权限为属主读写执行,属组读写,其他只读,且具有suid
  chmod 4764 /tmp/issue
  3、复制文件/etc/fstab为/tmp/fstab,修改/tmp/fstab的权限为属主读写执行,属组读,其他只读,且具有sgid和sticky。
  cp /etc/fstab /tmp/fstab
  chmod 3744 /tmp/fstab
  FACL文件访问控制列表
  用于在原有的访问控制机制之外增加一种文件访问控制机制。由于普通用户创建的文件不可以修改自身的权限(chmod)。就可以使用acl来限制其他用户的访问。
  1、通过getfacl可以查看文件的权限。
  getfacl /tmp/test/123
  2、通过setfacl设置文件的访问权限。
  -m, --modify=acl      modify the current ACL(s) of file(s)
  setfacl -m u:username:mode /path/to/file    #为用户username设定具有mode的权限
  setfacl -m g:groupname:mode /path/to/file   #为组groupname设定具有mode的权限
  -M, --modify-file=fileread ACL entries to modify from file
  -x, --remove=acl      remove entries from the ACL(s) of file(s)
  setfacl -x u:username /path/to/file         #取消某一个用户的acl权限。
  -X, --remove-file=fileread ACL entries to remove from file
  -b, --remove-all      remove all extended ACL entries
  -k, --remove-default    remove the default ACL
  --set=acl         set the ACL of file(s), replacing the current ACL
  --set-file=file   read ACL entries to set from file
  --mask            do recalculate the effective rights mask
  -n, --no-mask         don't recalculate the effective rights mask
  -d, --default         operations apply to the default ACL
  -R, --recursive         recurse into subdirectories
  -L, --logical         logical walk, follow symbolic links
  -P, --physical          physical walk, do not follow symbolic links
  --restore=file      restore ACLs (inverse of `getfacl -R')
  --test            test mode (ACLs are not modified)
  -v, --version         print version and exit
  -h, --help            this help text
  对于新加入的磁盘默认情况下是不支持acl功能的,需要通过在挂载的时候添加挂载选项-o acl才可以。
  比如:
  mount -o acl /dev/sdb1 /mnt/sdb1
页: [1]
查看完整版本: 九、shell编程