+, -, *(乘), /(除), **(乘方), %(取模)
let var=算术运算符表达式
高级let用法:let i+=2
+=,-=,*=,/=,%=,**=
自增:let var++
var=$[算术运算符表达式]
var=$((算术运算符表达式))
var=$(expr $ARG1 OP $APG2)
注意:乘法符号在某些场景中需要使用转义符
练习1:写一个脚本文件,完成如下功能:添加3个用户,求这3个用户的UID之和。
#!/bin/bash id testUser1 > /dev/null || useradd testUser1 id testUser2 > /dev/null || useradd testUser2 id testUser3 > /dev/null || useradd testUser3 uid1=`grep "testUser1" /etc/passwd | cut -d: -f3` uid2=`grep "testUser2" /etc/passwd | cut -d: -f3` uid3=$(grep "testUser3" /etc/passwd | cut -d: -f3) #方法1 #let num=$uid1+$uid2+$uid3 #方法2 #num=$[$uid1+$uid2+$uid3] #方法3 num=$(($uid1+$uid2+$uid3)) #方法4 #num=$(expr $uid1 + $uid2 + $uid3) echo $num
练习2:写一个脚本文件,完成如下功能:求/etc/passwd文件中第10行和第20行的用户的UID之和
#!/bin/bash #先用head取前10行,再用tail取最好一行,然后再用cut切 la=`head -10 /etc/passwd | tail -1 | cut -d: -f3` lb=`head -20 /etc/passwd | tail -1 | cut -d: -f3` echo $la echo $lb let lc=$la+$lb echo $lc
练习3:写一个脚本文件,完成如下功能:求/etc/passwd文件中,uid最大的2个uid之和
#!/bin/bash #先用冒号把文件分成多列,用第三列从大到小排序后,分别取第一行和第二行,最后在用cut切开 la=`sort -t: -k3 -nr /etc/passwd | head -1 | cut -d: -f3` lb=`sort -t: -k3 -nr /etc/passwd | head -2 | tail -1 | cut -d: -f3` echo $la echo $lb let lc=$la+lb echo $lc
练习4:写一个脚本文件,完成如下功能:通知2个文件里的空白行数之和
#!/bin/bash #用grep找出空白行(使用正则表达式),然后再用wc数一数有多少行 la=`grep -e "^[[:space:]]*$" /etc/rc.d/init.d/functions | wc -l` lb=`grep -e "^[[:space:]]*$" /etc/inittab | wc -l` echo $la echo $lb let lc=$la+$lb echo $lc
条件语句
测试表达式:
- test expression
- [ expression ]
- [[ expression ]]
注意:中括号中间的空格,没有空格就是语法错误
bash的条件测试类型
数值比较大小
例子:[ 2 -ne 3 ]和test 2 -ne 3效果一样
#!/bin/bash if [ 2 -ne 3 ]; then echo 11 else echo 22 fi if test 2 -ne 3; then echo 111 else echo 222 fi
- -eq:等于 [ $num1 -eq $num2 ]
- -ne:不等于[ $num1 -ne $num2 ]
- -gt:大于[ $num1 -gt $num2 ]
- -ge:大于等于[ $num1 -ge $num2 ]
- -lt:小于[ $num1 -lt $num2 ]
- -le:小于等于[ $num1 -le $num2 ]
字符串比较
== :等于
> :大于
< :小于
!= :不等于
=~ :左侧字符串是否被右侧的正则表达式所匹配。
-z "STRING" :指定字符串为空则为真
-n "STRING":指定字符串不为空则为真
做字符串比较的变量,最好加上“”。不加的话,如果做比较的某个变量没有被定义的话,执行就会出错。
下面的例子,tom是不存在的变量,不加括号就出错误了,加了就没有错误。
$ [ tom = $tom ] -bash: [: tom: unary operator expected $ [ tom = "$tom" ] $ echo $? 1
字符串比较,最好要用[[]]。
下面的例子,说明了用[]无法比较
$ [ a > b ] $ echo $? 0 $ [ a < b ] $ echo $? 0 $ [ "a" < "b" ] $ echo $? 0 $ [ "a" > "b" ] $ echo $? 0
下面的例子,说明用[[ ]]达到了预期。
$ [[ a < b ]] $ echo $? 0 $ [[ a > b ]] $ echo $? 1 $ [[ "a" > "b" ]] $ echo $? 1 $ [[ "a" < "b" ]] $ echo $? 0
字符串空的判断:
$ [[ -z "$tom" ]] $ echo $? 1 [ys@localhost ~]$ [[ -n "$tom" ]] [ys@localhost ~]$ echo $?
正则表达式的匹配:
$ tom=ooo [ys@localhost ~]$ [[ $tom =~ o.* ]] [ys@localhost ~]$ echo $? 0 [ys@localhost ~]$ tom=jerry [ys@localhost ~]$ [[ $tom =~ o.* ]] [ys@localhost ~]$ echo $? 1
文件测试
文件存在性检查:-a FILE,或者,-e FILE。存在返回0.
例子:[ -a /etc/passwd ],[ -e /etc/passwd ]
文件存在性和类型检查
-b FILE:文件存在,且类型是块设备,则返回0.
-c FILE:文件存在,且类型是字符设备,则返回0.
-d FILE:文件存在,且类型是目录,则返回0.
-f FILE:文件存在,且类型是普通文件,则返回0.
-h或 -L FILE:文件存在,且类型是符号链接,则返回0.
-p FILE:文件存在,且类型是命名管道,则返回0.
-S FILE:文件存在,且类型是本地套接字,则返回0.
$ [ -b /dev/sda ] [ys@localhost scripts]$ echo $? 0 [ys@localhost scripts]$ [ -b /dev/sdad ] [ys@localhost scripts]$ echo $? 1 [ys@localhost scripts]$ [ -b 2.sh ] [ys@localhost scripts]$ echo $? 1
文件权限检查
-r FILE:文件存在,且当前用户(运行此shell进程的用户)可读,则返回0.
-w FILE:文件存在,且当前用户(运行此shell进程的用户)可写,则返回0.
-x FILE:文件存在,且当前用户(运行此shell进程的用户)可执行,则返回0.
特殊权限检查
-u FILE:文件存在,且拥有suid权限,则返回0.
-g FILE:文件存在,且拥有sgid权限,则返回0.
-k FILE:文件存在,且拥有sticky权限,则返回0.
文件是否有内容
-s FILE:文件存在,且有内容,则返回0
时间戳
-N FILE:文件自从上一次读取操作后,是否被修改过。
从属关系
-O FILE:当前用户是否文件属主
-G FILE:当前用户是否在文件属组里。
双目
FILE1 -ef FILE2:如果FILE1和FILE2是指向同一个文件系统的相同inode的硬链接,则返回0.
FILE1 -nt FILE2:如果FILE1的修改时间戳新于FILE,则返回0
FILE 1 -ot FILE2:如果FILE1的修改时间戳旧于FILE,则返回0
组合测试条件
第一种方式:
- [ expression1 ] && [ expression2 ]
- [ expression1 ] || [ expression2 ]
- ! COMMOND
第二种方式:
- 与运算:[ expression1 -a expression2 ]
- 或运算:[ expression1 -o expression2 ]
练习:判断主机名称是否为空,或者是否是localhost.localdomain
#!/bin/bash hostname=`hostname` if [ -z "$hostname" -o "$hostname" == "localhost.localdomain" ]; then hostname=11111 else echo "ng" fi echo $hostname
向脚本文件传递执行时候的参数
使用位置参数变量:$1,$2,...${10},${11}.
10之后的参数必须加上{}。
$0:是脚本本身的路径加脚本文件的名字。
$#:是参数的个数
$*:拿到所有参数。但把所有参数汇总成了一个串
$@:拿到所有参数。但没有把参数汇总成一个串。
当执行下面命令后,$1的值就是111;$2的值就是222;$3的值就是333;
$ ./script.sh 111 222 333
shift用法:shift n:踢掉前n个位置参数变量
下面的内容保存在shift.sh中
#!/bin/bash echo $1 $2 shift 1 echo $1 shift 1 echo $1
执行shift.sh的结果:
# bash shift.sh 111 222 333 111 222 222 333
练习:传递2个文本文件的路径给脚本,计算出空白行数之和。
#!/bin/bash la=`grep -e "^[[:space:]]*$" $1 | wc -l` lb=`grep -e "^[[:space:]]*$" $2 | wc -l` echo $la echo $lb let lc=$la+$lb echo $lc
执行结果:
# bash sumforarg.sh /etc/rc.d/init.d/functions /etc/inittab 91 0 91
if语法
if con1 ; then elif con2 ; then else fi
练习:查看给定用户是否存在,不存在则创建此用户。
#!/bin/bash if ! grep "^$1\>" /etc/passwd &> /dev/null ; then useradd $1 # 设定用户$1的密码是111 echo "111" | passwd --stdin $1 &> /dev/null echo "add user $1 donw!" fi
练习:比较2个数字的大小
#!/bin/bash #声明一个变量,是整数。 declare -i max #参数个数小于2 if [ $# -lt 2 ]; then echo "at least one argu" exit 1 fi #参数1大于参数2 if [ $1 -ge $2 ]; then max=$1 else max=$2 fi echo "max number is $max"
练习:判断给定用户名的id号是奇数还是偶数
#!/bin/bash if [ $# -lt 1 ]; then echo "at least one argu" exit 1 fi #取得用户的id uid=$(grep "^$1\>" /etc/passwd | cut -d: -f3) echo $uid #判断奇偶数 if [ $[$uid % 2] -eq 0 ]; then echo "oushu" else echo "jishu" fi
运行结果:
# bash jigou.sh ys 1000 oushu # bash jigou.sh fedora 1005 jishu
练习:给2个文本文件路径,如果文件不存在,则结束脚本;都存在则返回每个文件的行数,并找出行数多的文件
#!/bin/bash if [ $# -lt 2 ]; then echo "at least two argu" exit 1 fi if ! [ -e $1 -a -e $2 ]; then exit 1 else la=`wc -l < $1` lb=`wc -l < $2` echo "$1 行数:$la;$2 行数:$lb" if [ $la -ge $lb ]; then echo "$1 行数多" else echo "$2 行数多" fi fi
运行结果:
# bash sum1.sh /etc/passwd /etc/fstab /etc/passwd 行数:56;/etc/fstab 行数:13 /etc/passwd 行数多
case语法
case $var in pat1) ;; pat2) ;; pat3) ;; *) ;; esac
pat支持globbing风格:
- *:匹配任意长度的任意字符
- ?:匹配任意单个字符
- []:匹配指定范围内的任意单个字符
- [^]:匹配指定范围外的任意单个字符
- {}:表示符合括号内包含的多个文件
- aaa|bbb:aaa或bbb
执行完脚本文件后,返回值是啥?
默认是脚本文件里最后一条命令的返回值。
可以自定义返回值:使用exit n命令,n为数字。
当shell进程遇到exit命令时,进程会立即终止,因此exit后面的命令就不执行了。