目录

shell脚本基础

shell脚本基础

1.shell条件测试

1.1命令执行结果判定

&&在命令执行后如果没有任何报错时会执行符号后面的动作

||在命令执行后如果命令有报错会执行符号后的动作

ping -c1 -w1 $* &> /dev/null && {
  echo -e "$* is up"
}||{
  echo -e "$* is done"
}

对命令执行结果的判定

脚本练习:检查用户是否存在,如果不存在就创建它,并且将密码设置为用户名

id $1 &> /dev/null &&{
  echo $1 is exist
}||{
  echo $1 is not exist
  useradd $1
  echo $1 | passwd --stdin $1 &> /dev/null && echo $1 is created
}

1.2条件判定方法

脚本后的字符个数为 $#

test = [],扩展的表达式要用[[ ]]括起来

[root@node ]# [[ $a = 1|2 ]] && echo yes || echo no

判断a是不是在0-10之间

[root@node ~]# (($a<10&&$a>0)) && echo yes || echo no

(( ))只适用于整数

1.3文件判断表达式

-a/-e 文件是否存在 -L 软连接 -r 读权限

-b 扩展设备 -d 目录 -w 写权限

-c 字符设备 -f 普通目录 -x执行权限

-s 大s套接字小s文件大小不为零

-u 设置了特殊权限的suid

[root@node ~]# [ -e “/mnt/file” ]&& echo yes || echo no

脚本练习:脚本后写一个文件名称,如果存在输出文件的类型,如果不存在则输出文件不存在

[ -e "$1" ] || {
  echo $1 is not exist
  exit
}
[ -L "$1" ] &&{
  echo $1 is link file
}
[ -f "$1" ] &&{
  echo $1 is common file
  exit
}
[ -d "$1" ] &&{
  echo $1 is dir file
}
​

1.4字符串测试表达式

[root@node ~]# [ -z “$c” ] && echo yes || echo no

[root@node ~]# [ -n “$c” ] && echo yes || echo no

-n 判定是否不为空

-z 判定是否为空

= !=

测试字符串

1.5整数测试表达式

-eq ==或= -ge >=

-ne != -le <=

-gt > -lt <

[root@node ~]# [ “$a” -lt “1” ] && echo yes || echo no

[root@node ~]# [ “$a” -gt “1” ] && echo yes || echo no

[root@node ~]# [ “$a” -ge “1” ] && echo yes || echo no

[root@node ~]# [ “$a” -le “1” ] && echo yes || echo no

[root@node ~]# [ “$a” -eq “1” ] && echo yes || echo no

[root@node ~]# [ “$a” -ne “1” ] && echo yes || echo no

man test(查看帮助)

1.6判定中的逻辑操作符

[root@node ~]# [[ “$a” -gt 0 ]]&&[[ “$a” -lt “10” ]] && echo yes || echo no yes

[root@node ~]# (( “$a”>0 && “$a”<10 )) && echo yes || echo no yes

[root@node ~]# [ “$a” -gt 0 -a “$a” -lt “10” ] && echo yes || echo no yes

[root@node ~]# test “$a” -gt 0 -a “$a” -lt “10” && echo yes || echo no yes

[root@node ~]# [ ! “$a” -lt “0” ] && echo yes || echo no yes(条件反选)

2.shell脚本中的运行流程控制

1.1if判定语句

脚本默认的程序执行方式是自上而下的

if单分支结构

if [ "$USER" = "root" ]
then
  echo supper user
fi

if双分支结构

if [ "$1" = "root" ]
then
  echo supper user
elif [ -z "$1" ]
then
  echo pleas input username
else
  echo unknow error
fi

练习 :if脚本代码

read -p "please input username: " USERNAME
read -p "what do you want [D]elete or [C]create:" ACTION
​
if [[ -z "$USERNAME" ]]
then
  echo error: please input username
  exit
elif [[ ! "$USER" = "root" ]]
then
  echo  "error: please run $0 with root"
elif [[ "$ACTION" =~ d|D  ]]
then
​
   if id $USERNAME &> /dev/null
   then
     userdel -r $USERNAME
     echo $USERNAME is deleted
   else
     echo $USERNAME is not exist 
   fi
​
elif [[ "$ACTION" =~ C|c ]]
then
​
   if id $USERNAME &> /dev/null
   then
     echo $USERNAME is exist
   else
    read -p "please input password:" PASS
    useradd $USERNAME
    echo $PASS | passwd --stdin $USERNAME &> /dev/null
   fi
​
else
  echo "error: please input C|D for action!!"
fi
​

2.2shell脚本中的选择判断(case语句)

用if做判断选择执行效率低,则需要使用case语句

case $1 in
    linux|Linux|LINUX)           一个“)”是一个按钮
    echo zee
    ;;
    zee)
    echo linux
    ;;
    *) 其他和*都匹配
    echo error
esac
​

case可以解决恰巧在最后,执行效率会比较低的问题

  • case $1 in

  • echo liux

  • case $1 in

  • echo zee

  • ‘[’ linux = linux ‘]’

  • echo zee

  • ‘[’ zee = linux ‘]’

  • ‘[’ zee = zee ‘]’

  • echo linux

2.3脚本中的循环语句

2.3.1无条件for循环

1.罗列变量的写法

for USERNAME in test1 test2 test3
do
  echo $USERNAME
done

2.连续选择的写法

for USERNAME in {1..10}
do
  echo $USERNAME
done
​

3.用命令的执行结果充当变量的值(反引号提取执行的结果)

一次执行一个

for USERNAME in `ls /root`
do
  echo $USERNAME
done
​

4.用seq

for USERNAME in `seq 1 2 10`
do
  echo $USERNAME
done

5.用运算的方式

for ((USERNAME=1;USERNAME<=10;USERNAME++))
do
  echo $USERNAME
done
2.3.2有条件的循环while

条件成立

while [ "$1" = "go" ]    while [ "1" = "1"](直接执行)  while [ "$1" = "start" ] (有动作的执行)
do
  for N in {1..10}
  do
      echo $N
  done
done

条件不成立用until

until [ "$1" = "go" ]
do
  for N in {1..10}
  do
      echo $N
  done
done

示例

while [ "$1" = "go" ]
do
  clear (清空屏幕)
  ls -l /root
  sleep 1 (等1秒)
done

练习 :1分10秒倒计时

echo -ne (不换行 \生效)

[ -a ]并且

SEC=10
MIN=1
SECS=$[ $MIN*60+$SEC]
for ((;SECS>0;SECS--))
do
    sec=$[$SECS%60]
    min=$[$SECS/60]
    echo -ne "after $min:$sec is end"
    echo -ne "\r"
    sleep 1
done

2.4循环中的控制器

1.exit

for n in {1..10}
do
  if [ "$n" -eq "4" ]
  then
    echo luck
    exit (退出脚本)
  fi
  echo $n
done

2.break

for n in {1..10}
do
  if [ "$n" -eq "4" ]
  then
    echo luck
    break(退出循环)
  fi
  echo $n
done

3.continue

for n in {1..10}
do
  if [ "$n" -eq "4" ]
  then
    echo luck
    continue(下面放弃掉,提前进入下一次循环)
  fi
  echo $n
done

4.return

FOR()
{
for n in {1..10}
do
  if [ "$n" -eq "4" ]
  then
    echo luck
    return(退出函数
  fi
  echo $n
done
}
FOR

2.5自动应答

如果我们想要依照问题的内容回答问题需要借助软件expect(一种环境)

[root@node mnt]# dnf install expect -y 下载软件

[root@node mnt]# vim answer.exp

#!/usr/bin/expect
spawn /mnt/ask.sh #spawn监控ask.sh
expect {
    "name" { send "zee\r";exp_continue }
    "old" { send "18\r";exp_continue }
    "subject" { send "linux\r";exp_continue }
    "happy" { send "happy\r" }
}
expect eof  #应答完毕后退出
interact #保留当前的绘画环境

[root@node mnt]# expect answer.exp

shell版本

#!/bin/bash
/usr/bin/expect <<EOF
spawn /mnt/ask.sh    将spawn写入expect执行
expect {
    "name" { send "zee\r";exp_continue }
    "old" { send "18\r";exp_continue }
    "subject" { send "linux\r";exp_continue }
    "happy" { send "happy\r" }
}
expect eof
EOF

函数的调用

AUTO_ANSWER()
{
/usr/bin/expect <<EOF
spawn /mnt/ask.sh    将spawn写入expect执行
expect {
    "name" { send "$1\r";exp_continue }
    "old" { send "$2\r";exp_continue }
    "subject" { send "$3\r";exp_continue }
    "happy" { send "$4\r" }
}
expect eof
EOF
}
AUTO_ANSWER zee 18 linux happy