Linux之bash脚本
Shell就是用户与系统交互的应用程序bash是shell应用程序其中的一种。最简单的shell脚本就是系统支持命令的叠加。
例如:vim command.sh
#!/bin/bash 告诉shell用bash解释器运行此脚本(开头第一行) # #号注释 ls /var cat /var/log/maillog
运行此脚本方式有两种
1 第一为此脚本添加可执行权限 chmod +x command.sh
然后加路径可以是绝对路径也可是相对路径
./command.sh 或是 /root/command.sh
2 直接告诉shell用bash解释器解释
bash ./command.sh
bash -n 检查语法格式
bash -x debug模式运行 用于调试脚本
运行结果为
你会发现这样的脚本只能按顺序一条一条的执行,不够灵活,不能根据特定的条件执行不同的操作。Bash支持条件分支结构。If—then
If结构的语法格式分为三种:
if command ;then Command fi If command ;then Command Else Command Fi If command ;then Command Elif command;then Command Else Command fi
If语句会根据他后面命令的反回状态来决定接下来该如何进行下面的语句当返回状态为真即0时执行then后的语句不为0则执行其他语句。
注意if后面跟的是一条命令 也许你会看的 if [ ]这样的形式
#!/bin/bash # A=2 B=3 echo "######if [];then###########" if [ $A -gt $B ];then echo "A > B" else echo "A <= B" fi echo "#####if command;then#######" if test $A -gt $B ;then echo "A > B" else echo "A <= B" fi
执行结果:
他们之间执行的结果是相同的;bash 用[]代替了test
条件判断
用于数值之间的判断用[]括起来
文件属性判断
组合条件测试
[ 条件1 -a 条件2 ] [ 条件1 -o 条件2 ] [-not 条件1]
复合命令测试
命令1 &&命令2 命令1||命令2 !命令1
示例:给定一个用户,如果其shell为/bin/bash且其ID号大于等于500,则说这是一个可登录普通用户;否则,则显示其为非登录用户或管理员
#!/bin/bash # if ! id $1 &> /dev/null; then echo "No this user." exit 3 fi userShell=$(grep "^$1\>" /etc/passwd | cut -d: -f7) userID=$(id -u $1) if [ "$userShell" == '/bin/bash' -a $userID -ge 500 ]; then echo "Login user." else echo "not login user." fi
多分支条件测试:
Case variable in
Pattern1 | parttern2 ) commands1;;
Pattern3 ) commands2;;
*) commands3;;
Esac
示例:请用户输入一个颜色并用指定的颜色显示用户输入
#!/bin/bash # read -p "Plese input a color: " COLOR case $COLOR in red) echo -e "\033[31m this color\033[0m";; green) echo -e "\033[32m this color\033[0m";; yellow) echo -e "\033[33m this color\033[0m";; blue) echo -e "\033[34m this color\033[0m";; *) echo -e "sorry i don't know" Esac
循环语句:for 用于循环次数已知的情况
For variable in list;
Commands
Done
For (( variable的初始值 ; variable取值范围;variable 自加或自减));do
Commands
done
示例:使用for循环实现类似于awk的功能取出/etc/passwd中每行的各个元素
#!/bin/bash # OLDIFS=$IFS IFS=$'\n' for i in $(cat /etc/passwd);do echo -e "\033[31m$i\033[0m" echo "----------------------------------------------------" IFS=: for k in $i;do echo $k done echo "----------------------------------------------------" done IFS=$OLDIFS
示例:使用for循环打印99乘法表 #!/bin/bash # for ((i=1;$i <= 9;i++));do for ((k=1;$k <= $i;k++));do let "tmp=$i*$k" echo -ne "$i*$k=$tmp " done echo done
While 用于循环循环次数未知
While [ 条件测试 ];do
Commands
Done
表达的意思是当条件满足时执行循环体内的命令
示例:使用while打印 * ** *** **** ***** #!/bin/bash # declare -i LINE=1 while [ $LINE -le 5 ];do declare -i INLIN=1 while [ $INLIN -le $LINE ];do echo -n "*" let INLIN++ done let LINE++ echo Done
执行结果:
Until 循环与while循环相同用法只不过他的测试条件不满足时才执行循环体内命令
#!/bin/bash # declare -i LINE=1 until [ $LINE -gt 5 ];do declare -i INLIN=1 until [ $INLIN -gt $LINE ];do echo -n "*" let INLIN++ done let LINE++ echo Done
执行结果与上一个例子相同
Bash用户交互方式
命令行参数传递 和 读取用户输入
命令行参数传递:
Command par1 par2 ... par10 .... Parn
$1 $2 ... ${10}..... ${n}
$0:脚本名称
$#:参数个数
$$:脚本执行时的PPID
$@:有参数
$*: 所有参数
注意:$*与$@区别
#/bin/bash # echo '############$0###################' echo "$0" echo '############$$###################' echo "$$" echo '############ $# #################' echo "$#" echo '####################$@############' for i in "$@";do echo "$i" done echo '####################$*############' for i in "$*";do echo "$i" Done
读取用户输入:
Read 命令
read -p 允许在命令行中直接指定一个提示
-s 静默模式 类似于登录系统时输入密码看不到密码但是输入了
-t 等待时长
函数:使脚本模块化 同一功能重复需要执行时直接调用就行不需重复编写代码
定义函数的方法
Functionname ()
{
Commands
}
函数的引用直接在脚本中使用函数名引用
如何向函数传递参数
函数名后加参数就可以了 跟命令行参数传递类似
Bash数组
数组的定义方法:declare -a arryname 定义普通数组
declare -A arryname 定义关联数组
数组的复制方法:三种
单独对每个数组元素赋值例如:arry[0]=1 arry[2]=2 arry[3]=3.......
对所有元素一次性赋值例如:arry=( 1 2 3 ....)
对指定索引元素进行赋值例如:arry([0]=1 [4]=3...........)
数组的访问${arry[1]}
数组的长度${$arry[*|@]}
从数组中挑选某些元素${$arry[*|@]}:offset:num 从offset处取出num个值
Bash 内建命令
综合示例:创建小型linux
#!/bin/bash # Description: disk opration # Author: he feng # declare -i Signal=0 MntDIR1="/mnt/boot" MntDIR2="/mnt/sysroot" #################judce Disk############# DISKEX () { read -p "Plz input a disk: " Disk until [ "$Disk" == "quit" ]&&return 5;do while [ $Signal -eq 0 ];do if fdisk -l |grep -E "^Disk $Disk:";then DiskOP break 2 else echo -ne "\033[31m This disk is not exists input another: \033[0m " read Disk fi done done } #################Chocie OP################# DiskOP () { fdisk -l $Disk|grep "$Disk" read -p "!!!!This will erase date of this disk continue??!!!!! y|n: " Chioce while true;do case $Chioce in y) REBUILT break ;; quit|n) echo "chioce N quit!!" exit 2 ;; *) read -p "Input is wrong PLz iuput y|n: " Chioce continue ;; esac done } REBUILT () { # Flush # Flush MountC=$(mount | grep -E "$Disk" |wc -l) if [ $MountC -ne 0 ];then for ((k=1;$k<=$MountC;k++));do umount $Disk$k done fi cat <<EOF ############################### # erase disk # ############################### EOF dd if=/dev/zero of=$Disk bs=512 count=1 &>/dev/null sync sleep 3 [ $? -eq 0 ]&&echo "erase is ok!!" #UPDATE cat <<EOF ############################### # make FS # ############################### EOF echo -e "n \n p \n 1 \n \n +20M \n n \n p \n 2 \n \n +512M \n n \n p \n 3 \n \n +128M \n t \n 3 \n 82 \n w"|fdisk $Disk &>/dev/null fdisk -l $Disk | grep "$Disk" # sleep 5 mke2fs -t ext4 ${Disk}1 &>/dev/null mke2fs -t ext4 ${Disk}2 &>/dev/null #UPDATE # sleep 10 [ -d $MntDIR1 ]||mkdir $MntDIR1 [ -d $MntDIR2 ]||mkdir $MntDIR2 mount ${Disk}1 $MntDIR1 mount ${Disk}2 $MntDIR2 } #Flush () #{ # dmsetup status # dmsetup remove_all #} ##############INSTALL GRUB########################## INGRUB () { echo -e "\033[32m###################install grub#################\033[0m" grub-install --root-directory=$(dirname $MntDIR1) $Disk # ([ $? -eq 0 ]&&echo -e "\033[31mgrub install success!!\033[0m")||exit 3 cat >${MntDIR1}/grub/grub.conf<<EOF default=0 timeout=10 title MY Centos root (hd0,0) kernel /vmlinuz-mycentos ro root=/dev/sda2 selinux=0 init=/bin/bash initrd /initramfs-mycentos.img EOF cp /boot/vmlinuz-`uname -r` $MntDIR1/vmlinuz-mycentos cp /boot/initramfs-`uname -r`.img $MntDIR1/initramfs-mycentos.img ROOTBUILT } #############BUILT THE ROOTFS######################## ROOTBUILT () { for i in $(ls /);do mkdir -p ${MntDIR2}/$i done } ##############PORTABLITY APP########################## PORAPP () { read -p "Plz input the app: " APPLI until [ "$APPLI" == quit ];do while true;do if which --skip-alias $APPLI ;then WHERE=$(which --skip-alias $APPLI) DIRAPP=$(dirname $WHERE) [ -d ${MntDIR2}${DIRAPP} ]||mkdir -p ${MntDIR2}${DIRAPP} [ -e ${MntDIR2}${WHERE} ]||cp $WHERE ${MntDIR2}${DIRAPP} LIBS=$(ldd $WHERE|grep -oE "(/[[:alnum:]]*/[^[:space:]]*[[:space:]])") for i in $LIBS;do DIRLIB=$(dirname $i) [ -d ${MntDIR2}$DIRLIB ]||mkdir -p ${MntDIR2}$DIRLIB cp $i ${MntDIR2}$i done read -p "Do you want to another app? or quit: " APPLI continue 2 else read -p "Input is not app!! Plz input again or quit: " APPLI continue 2 fi done done } ##################MAIN################## MAIN () { DISKEX [ $? -eq 5 ]&&exit INGRUB PORAPP } MAIN