shell脚本编程
编译器-------解释器
静态语言:编译型语言,强类型(变量);事先转换成可执行格式。C/C++/JAVA/C#
动态语言:解释型语言,弱类型。边解释变执行。PHP,SHELL,python,perl
面向过程:shell,c;面向对象:java,python,perl,c++
变量赋值:VAR_NAME = VALUE;
bash变量类型:
环境变量:作用域为当前shell进程及其子进程。
export VARNAME=VALUE或者 VARNAME=VALUE export VARNAME "导出"定义为环境变量。
脚本在执行时候启动一个子shell进程:
[root@iZ233y80y23Z ~]# NAME=LINJUNBIN
[root@iZ233y80y23Z ~]# export NAME
[root@iZ233y80y23Z ~]# echo $NAME
LINJUNBIN
[root@iZ233y80y23Z ~]# bash //切换到子shell;
[root@iZ233y80y23Z ~]# echo $NAME //该环境变量依然有效。
LINJUNBIN
本地变量(局部变量):
整个bash进程:本地变量:VARNAME=VALUE
局部变量:作用域为当前代码段有效。local VARNAME=VALUE
位置变量:
$1,$2,....
特殊变量:(bash内置):$?:上一个命令的执行状态返回值状态值;
程序执行一般有两种返回值;执行状态$?=0-255
0:正确执行;1-255:错误执行;
1,2,127:系统预留。
$?:上次命令执行返回状态码;
$#:参数的个数
$*:参数列表
$@:参数列表
引用变量:${VAR_NAME},引用该变量。
[root@iZ233y80y23Z ~]# echo "there are some ${ANIMAL}s."
there are some PIGs.
[root@iZ233y80y23Z ~]# echo 'there are some ${ANIMAL}s.'
there are some ${ANIMAL}s.
注意:''单引号和""双引号的区别。
输出重定向:
>:>>:2>:2>>,&>
输入:
/dev/null:软件设备;/dev/null:数据黑洞;
eg:判断是否含有某个用户。
[root@iZ233y80y23Z ~]# id student &> /dev/null
[root@iZ233y80y23Z ~]# echo $?
1
撤销变量:
unset VARNAME不用加$;
查看变量:
使用set命令;set:包含环境变量和本地变量;
查看环境变量:printenv ,env, export;三个都可以。
eg:
[root@iZ233y80y23Z ~]# ANIMALS=pig
[root@iZ233y80y23Z ~]# ANIMALS=$ANIMALS:goat
[root@iZ233y80y23Z ~]# echo $ANIMALS
pig:goat
脚本:命令的堆砌,
判断用户是否存在:id user1 &> /dev/null && echo "hello user1";
[root@iZ233y80y23Z test]# id root &> /dev/null && echo 'root'
root
shell条件判断
判断执行结果$?来判断执行的状态码来判断执行是否成功或者失败。
整数测试:
-eq:测试两个整数是否相等;
-ne:测试两个整数是否不等,不等,为真;相等,为假;
-gt:测试一个数是否大于另一个数;
-lt:测试一个数是否小于另一个数;
-ge:大于或者等于;
-le:小于或者等于;
eg:
[root@iZ233y80y23Z test]# A=3
[root@iZ233y80y23Z test]# B=4
[root@iZ233y80y23Z test]# [ $A -eq $B ]
[root@iZ233y80y23Z test]# echo $?
1
[root@iZ233y80y23Z test]# B=3
[root@iZ233y80y23Z test]# [ $A -eq $B ]
[root@iZ233y80y23Z test]# echo $?
0
字符测试:
文件测试:
条件测试表达式:注意:两边要空格。
[ expression表达式 ],[[ expression ]] , test expression
表达式:
命令间的逻辑关系;
逻辑与:&&,第一个条件为假第二个条件不用执行,两个都必须为真。
逻辑或:|| 第一个条件为假,第二个条件必须得判断。两个中一个为真就可以。
eg:如果用户user6不存在,就添加用户user6
! id user6 &> /dev/null && useradd user6
id user6 &> /dev/null || useradd user6
LINE=`wc -l /etc/inittab`;将这个命令运行结果放在变量中。
eg:如果文件/etc/inittab文件的行数大于100,就显示好大的文件,否则显示小文件。
[root@iZ233y80y23Z test]# cat souce.sh
#!/bin/bash
LINES=`wc -l /etc/inittab`
echo $LINES
FINLINES=`echo $LINES | cut -d' ' -f1`
echo $FINLINES;
[ $FINLINES -gt 100 ] && echo "/etc/inittab is a big file." || echo "/etc/inittab is a small file"
[root@iZ233y80y23Z test]# bash souce.sh
17 /etc/inittab
17
/etc/inittab is a small fi
eg:为系统添加用户:
`! id user1 &> /dev/null && useradd user1 && echo "user1" | passwd --stdin user1 &> /dev/null || echo 'user1 exists`
添加完用户,管道到passwd。进行设置密码;同时输出总行数。
[root@iZ233y80y23Z test]# bash addUser.sh
user1 exists
39
[root@iZ233y80y23Z test]# cat addUser.sh
#!/bin/bash
! id user1 &> /dev/null && useradd user1 && echo "user1" | passwd --stdin user1 &> /dev/null || echo 'user1 exists'
! id user2 &> /dev/null && useradd user2 && echo "user2" | passwd --stdin user2 &> /dev/null || echo 'user2 exists'
! id user3 &> /dev/null && useradd user3 && echo "user3" | passwd --stdin user3 &> /dev/null || echo 'user3 exists'
#获取总行数
LINES=`wc -l /etc/passwd | cut -d' ' -f1`
echo $LINES;
eg:
#判断当前用户是否为root用户;
[root@iZ233y80y23Z test]# bash is_root.sh
is root
[root@iZ233y80y23Z test]# cat is_root.sh
#!/bin/bash
USER_UID=`id -u`;
[ $USER_UID -eq 0 ] && echo 'is root' || echo "is not root and this uid is ${UID}"
注意:报错is_root.sh: line 2: UID: readonly variable,原来是UID变量设置和环境变量重名,主要变量命名。
if条件判断
单分支的if语句:
if 判断条件
then
statement1;statement2;
fi
双分支if语句:
if 判断条件; then
statement1;statement2;...
else
statement3;statement4;...
fi
多分支if语句
if 条件判断1; then
statement1;...
elif 判断条件2; then
statement2;...
elif 判断条件3; then
statement3;...
...
else
statement4;...
fi
eg:
#判断某个用户是否存在:
[root@iZ233y80y23Z test]# bash user.sh
user12 IS NOT exists
[root@iZ233y80y23Z test]# cat user.sh
#!/bin/bash
NAME=user12;
if id $NAME &> /dev/null; then
echo "$NAME is exists"
else
echo "$NAME IS NOT exists"
fi
#如果用户存在就显示存在,如果不存在就进行添加;
eg:
#判断当前系统是否有用户的默认shell为bash:如果有,就显示多少个,否则就显示没有这类用户
[root@iZ233y80y23Z test]# ./is_bash.sh
the shells of 10 users is bash shell
[root@iZ233y80y23Z test]# cat is_bash.sh
#!/bin/bash
#获取默认的shell为bash
grep "bash$" /etc/passwd &> /dev/null;
RETVAL=$?;
if [ $RETVAL -eq 0 ]; then
USERS=`grep "\<bash$" /etc/passwd | wc -l`
echo "the shells of $USERS users is bash shell";
else
echo "no bash user"
fi
[root@iZ233y80y23Z test]#
#验证/etc/inittab这个文件有没有空白行,多少空白行
[root@iZ233y80y23Z test]# cat has_space.sh
#!/bin/bash
grep "^$" /etc/inittab &> /dev/null;
HAS_SPACE=$?
if [ $HAS_SPACE -eq 0 ] ; then
SPACES=`grep "^$" /etc/inittab | wc -l`;
echo "total SPACES is $SPACES LINES";
else
echo "no any spaces in /etc/inittab";
fi
[root@iZ233y80y23Z test]#
注意:等号两边不能有空格;
#验证用户的uid是否等于GID,两种实现方式
[root@iZ233y80y23Z test]# cat uid_eq.sh
#!/bin/bash
USERNAME=user1
#USERID=`id -u $USERNAME`;
USERID=`grep "^user1" /etc/passwd | cut -d: -f3`
GROUPID=`grep "^user1" /etc/passwd | cut -d: -f4`
#GROUPID=`id -g $USERNAME`;
if [ $USERID -eq $GROUPID ] ; then
echo 'Good guy';
else
echo 'Bad guy';
fi
#注意:date +%s表示时间戳中1970开始的秒数;man date
echo $HISTSIZE;
#给定一个文件测试其是否存在
#单步执行;bash -x
eg:测试脚本的执行过程。bash -x
[root@iZ233y80y23Z test]# bash -x file_test.sh
+ FILE=/etc/inittab
+ '[' -e /etc/inittab ']'
+ echo OK
OK
[root@iZ233y80y23Z test]#
#给定一个文件,如果是否普通文件,就显示,如果是目录就显示,否则显示无法辨别该文件。
[root@iZ233y80y23Z test]# ./file_test.sh
common file
[root@iZ233y80y23Z test]# cat file_test.sh
#!/bin/bash
FILE=/etc/inittab
if [ ! -e $FILE ]; then
echo 'no such file';
exit 6;
fi
if [ -f $FILE ]; then
echo 'common file';
elif [ -d $FILE ]; then
echo 'directory';
else
echo 'unknown';
fi
注意:判断符!后面必须要有空格;
shell中进行算术运算
shell中默认所有的变量都是字符串;
[root@iZ233y80y23Z test]# A=3
[root@iZ233y80y23Z test]# B=4
[root@iZ233y80y23Z test]# echo $A+$B
3+4
一般使用1,2,3这三种方法:
1、算术运算let:
let C=$A+$B
2、$[算术运算表达式]
C=$[$A+$B]
3、$((算术运算表达式))
C=$(($A+$B))
4、expr 算术运算表达式,表达式中各操作数和运算符之间要有空格,而且使用命令引用
F=`expr $A + $B`
5、使用运算器bc
退出脚本
exit:退出脚本;
exit n;n为退出状态码;
如果脚本没有明确定义退出状态码,那么,最后一条命令的退出码即为脚本的退出状态码;
测试方法
使用中括号测试法:
[ expression ]:两边记得要用空格,命令测试法;
[[ expression ]]:关键字测试法;
test expression:
只有使用-gt,-le,-ne,-eq,-ge,-lt:需要加上中括号,其他的不一定需要加中括号。
if `grep "^$USERNAME\>" /etc/passwd` ; then
文件测试:
-e FILE:文件是否存在。
-f FILE:测试文件是否为普通文件
-d FILE:测试指定路径是否为目录;
-r FILE:测试当前用户对指定文件是否有读权限
-w FILE:测试当前用户对指定文件是否有写权限
-x FILE:测试当前用户对指定文件是否有执行权限
eg:
[ -e /etc/inittab ] ,[ -x /etc/rc.d/rc.sysinit ]
[root@iZ233y80y23Z test]# ./exitst_file.sh
NO /etc/iniittab
[root@iZ233y80y23Z test]# cat exitst_file.sh
#!/bin/bash
FILE=/etc/iniittab
if [ ! -e $FILE ] ; then
echo "NO $FILE"
exit 8;
fi
圆整:丢弃小数点后面内容;/
显示历史命令:
[root@iZ233y80y23Z test]# history | tail -1 | cut -d' ' -f2
1012
位置变量(参数)
位置变量$1,$2,...
./file_test.sh /etc/fstab /etc/inittab;
$1:/etc/fstab; $2:/etc/inittab;
shift:将参数列表中第一个参数弹出;相当于数组中的shift弹出第一个元素;
shift n:表示一次弹出n个参数;
#判定:接收一个参数,如果一个存在的文件就显示OK,如果不存在就显示no such file
eg:$#:显示所有参数个数;$*:参数列表 $@:参数列表;
[root@iZ233y80y23Z test]# ./exitst_file.sh /etc/inittab /ffff /ttddd
3
/etc/inittab /ffff /ttddd
/etc/inittab /ffff /ttddd
OK
[root@iZ233y80y23Z test]# cat exitst_file.sh
#!/bin/bash
echo $#
echo $*
echo $@
if [ ! $1 ]; then
echo 'please add parame file';
exit;
fi
if [ -e $1 ] ; then
echo "OK"
else
echo "no such file";
fi
[root@iZ233y80y23Z test]#
#测试shift
[root@iZ233y80y23Z test]# ./shift.sh 1 2 3 4 5
5
1
2
4
[root@iZ233y80y23Z test]# cat shift.sh
#!/bin/bash
echo $#;
echo $1;
shift
echo $1;
shift 2
echo $1