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脚本里面 执行 sudo linux执行bash脚本_命令行

你会发现这样的脚本只能按顺序一条一条的执行,不够灵活,不能根据特定的条件执行不同的操作。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脚本里面 执行 sudo linux执行bash脚本_bash脚本里面 执行 sudo_02

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

条件判断

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

bash脚本里面 执行 sudo linux执行bash脚本_命令行_03

文件属性判断

bash脚本里面 执行 sudo linux执行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

bash脚本里面 执行 sudo linux执行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

bash脚本里面 执行 sudo linux执行bash脚本_命令行_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

执行结果:

bash脚本里面 执行 sudo linux执行bash脚本_数组_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 内建命令

bash脚本里面 执行 sudo linux执行bash脚本_bash脚本里面 执行 sudo_08

bash脚本里面 执行 sudo linux执行bash脚本_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 <
###############################
#        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 <
###############################
#       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<
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