linux bash算术运算和条件语句
+, -, *(乘), /(除), **(乘方), %(取模)
-
let var=算术运算符表达式
高级let用法:let i+=2
+=,-=,*=,/=,%=,**=
自增:let var++
-
var=$[算术运算符表达式]
-
var=$((算术运算符表达式))
-
var=$(expr $ARG1 OP $APG2)
</font color=red>注意:乘法符号在某些场景中需要使用转义符
练习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的条件测试类型
-
数值比较大小
- -eq:等于 [ $num1 -eq $num2 ]
- -ne:不等于[ $num1 -ne $num2 ]
- -gt:大于[ $num1 -gt $num2 ]
- -ge:大于等于[ $num1 -ge $num2 ]
- -lt:小于[ $num1 -lt $num2 ]
- -le:小于等于[ $num1 -le $num2 ]
例子:[ 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
-
字符串比较
== :等于
> :大于
< :小于
!= :不等于
=~ :左侧字符串是否被右侧的正则表达式所匹配。
-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后面的命令就不执行了。