Linux之bash脚本

 

    Shell就是用户与系统交互的应用程序bashshell应用程序其中的一种。最简单的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  直接告诉shellbash解释器解释

   bash ./command.sh

   bash -n  检查语法格式

   bash -x  debug模式运行 用于调试脚本

 运行结果为

 ​ Linux之bash脚本_脚本


    你会发现这样的脚本只能按顺序一条一条的执行,不够灵活,不能根据特定的条件执行不同的操作。Bash支持条件分支结构。Ifthen

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


执行结果:

​ Linux之bash脚本_脚本_02


他们之间执行的结果是相同的;bash []代替了test 

条件判断

用于数值之间的判断用[]括起来

​ Linux之bash脚本_bash _03


文件属性判断

​ Linux之bash脚本_bash _04

组合条件测试

条件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


​ Linux之bash脚本_bash _05

示例:使用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

​ Linux之bash脚本_linux_06

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


执行结果:

​ Linux之bash脚本_linux_07

 

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之bash脚本_linux_08


​ Linux之bash脚本_脚本_09

综合示例:创建小型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