变量
进程结束,变量被销毁
普通变量,子进程中是无法访问的,得是环境变量才行
作用域:当前脚本中得为全局变量,环境变量为超全局,函数内得为局部
export varname=value 声明并赋值一个环境变量
name=xqw 定义赋值一个普通变量 export name 再声明为环境变量
局部变量 local varname=val
位置变量 $1 $2 ... 引用脚本的参数
变量的命名:仅包含数字,字母,下划线,不能以数字开头;不能跟已有的环境变量重名
$? 上一个进程(执行的命令)的执行状态返回值
执行程序,有两种返回
结果
状态 $? 如果是正确被执行,则返回0, 如果是错误,则1~255(1,2,127系统保留)
脚本执行时,启动一个新bash
命令行直接执行的,相当于当前bash的子bash,会继承父进程的环境变量
系统自动执行的脚本,是需要设置环境变量的,因为执行时,并没有上层的父bash进程
unset varname 销毁变量
set
printenv
env
export
export PATH=$PATH:/bin/go
shell中变量的值默认是字符串,并不能直接算术运算
执行脚本
./xx.sh
xx.sh 要将路径加入到PATH中
bash xx.sh
source xx.sh
. xx.sh
判断表达式
[ expression ]
[[ expression ]]
test expression
-eq -ne -gt -ge -lt -le
[ $a -eq $b ]
echo $?
逻辑判断
&&
短路现象: a && b a为真,则执行后面的b , a为假,则b不用执行
id user3 &> /dev/null && echo 'user3 is exists.'
||
短路现象: a || b a为真,则后面的不用判断,a为假,则需要执行后面的
id root &> /dev/null || echo 'root not exists.' && echo 'root is exists.'
如果用户不存在,就添加用户?
id user2 &> /dev/null || useradd user2
! id user3 &> /dev/null && useradd user3
判断文件超过100行,就是大文件?
[ `wc -l ./passwd | cut -d' ' -f1` -gt 100 ] && echo 'big file.' || echo 'small file.'
!id user1 && useradd user1 && echo 'user1' | passwd --stdin user1 || echo 'user1 exists.'
exit 退出当前进程脚本
exit 可以定义执行状态结果是什么;如果没有定义,则默认把exit前面那一条命令的退出执行状态当作整个脚本的执行状态结果
exit #
运算
let C=$A+$B
C=$[$A+$B]
C=$(($A+$B))
C=`expr $A + $B` expr命令 算术运算表达式 表达式中各操作数及运算符之间要有空格,而且要使用命令引用
文件测试
-e -f -d -r -w -x
[ -e file ]
[ -x file ]
脚本调试
bash -n xx.sh 检查语法,不执行脚本
bash -x xx.sh 单步,显示每一条执行的命令
注意:如果脚本中没有定义退出码,则最后执行的那一条命令的状态码,就是整个脚本的退出状态码
shift
执行其一次,$1 $2 $3 ... 位置变量的值整体向前移动一位
shift # 向前移动#位
特殊变量
$?
$1 $2
$# 参数个数
$* $@ 参数列表
练习
1. 传递三个参数给脚本,第一个为整数,第二个为算术运算符,第三个为整数,将计算结果显示出来,
要求保留两位精度,形如:./calc.sh 5 / 2
echo "scale=2;111/22" | bc
bc <<< "scale=2;111/22"
2. 传递3个参数给脚本,参数均为用户名,将此些用户的账号信息提取出来后,放置于 /tmp/testusers.txt文件中,并要求每一行行首有行号;
3. 判断当前主机的cpu生产商,其信息在/proc/cpuinfo文件中 vendor_id 一行中,
如果其生产商为AuthenticAMD,就显示其为AMD公司;
如果其生产商为GenuineIntel,就显示其为Intel公司;
否则,就说其为非主流公司;
cputype=`grep 'vendor_id' /proc/cpuinfo | head -1 | cut -d':' -f2 | sed -r 's@[[:space:]]+@@g'`
case $cputype in
AuthenticAMD)
echo "AMD.";;
GenuineIntel)
echo "intel.";;
*)
ehco "is not popular company.";;
esac
4. 给脚本传递三个整数,判断其中的最大数 和 最小数,并显示出来;
5. 写脚本,添加5个用户,user1~user5,每个用户的密码同用户名,用户添加完成后,显示用户成功添加
useradd user1 &> /dev/null && echo user1 | passwd --stdin user1 &> /dev/null && echo 'user1 add success.' || echo 'user1 exists.'
for i in {1..5}; doif id user$i &> /dev/null; then
echo "user$i exists."else
useradd user$i
echo "user$i" | passwd --stdin user$i &> /dev/null
echo "add user$i success."
fi
done
6. 添加3个用户,先判断其是否存在,不存在才添加,添加完成后,显示一共添加了几个用户,最后显示当前系统上共有多少个用户?
7. 给定一个用户,如果其uid为0,就显示为管理员,否则就显示其为普通用户
8. 删除某用户,一并删除其家目录,显示删除完成
9. 判断当前系统上是否有用户的默认shell为bash,如果有,就显示有多少个这类用户;否则,就显示没有这类用户;
10. 判断当前系统上是否有用户的默认shell为bash;如果有,就显示其中一个的用户名;否则,就显示没有这类用户;
11. 给定一个文件,判断这个文件中是否有空白行,如果有,则显示其空白行数,否则,显示没有空白行;
12. 给定一个用户,判断其UID与GID是否一样,如果一样,就显示此用户为“good guy”,否则,就显示此用户为“bad guy” , 进一步要求,不使用id命令获得其id号
13. 传递两个参数,显示两者之积,之和?
14. 不使用id命令,判断用户是否存在,并且判断其uid,gid是否一样
USERNAME=user1
if ! grep "^$USERNAME\>" /etc/passwd &> /dev/null; then
echo "No such user: $USERNAME."
exit 1
fi
USERID=`grep "^$USERNAME\>" /etc/passwd | cut -d: -f3`
GROUPID=`grep "^$USERNAME\>" /etc/passwd | cut -d: -f4`
if [ $USERID -eq $GROUPID ]; then
echo "Good guy."
else
echo "Bad guy."
fi