shell脚本基础

shell脚本基础

0x00 什么是shell

shell脚本就是将完成一个任务的所有命令按照执行的先后顺序,自上而下的写入到一个文本文件中,然后给予执行权限

0x01 shell脚本格式

开头必须指定脚本运行环境,以 #! 这个特殊符号组合来组成。如,#!/bin/bash 指定脚本运行解析由/bin/bash来完成。shell脚本中,最好加入脚本说明字段。# 代表注释。 #!是特例。脚本中最好不要带中文

#!/bin/bash
#Author: binbin_erices
#Created Time: 2020/2/22
#Release: 1.0
#Script Description: nginx  install script

1.1 脚本组成

#脚本环境 #!/usr/bin/env bash|python|perl
#注释说明
#执行代码

1.2 运行脚本

(1)给执行权限, ./1.sh

(2) 解释器直接运行 不需要给权限. sh 1.sh

查看支持的shell 和 当前使用的shell

zbb@ubuntu:~$ echo $SHELL
/bin/bash
zbb@ubuntu:~$ echo $0
bash
zbb@ubuntu:~$ cat /etc/shells
# /etc/shells: valid login shells
/bin/sh
/bin/dash
/bin/bash
/bin/rbash
@ubuntu:~$ echo -n "DATE IS: "; date  +%F
DATE IS: 2020-02-22
zbb@ubuntu:~$ echo "DATE IS: "; date  +%F
DATE IS: 
2020-02-22
zbb@ubuntu:~$ echo "DATE IS: `date +%F`"
DATE IS: 2020-02-22
zbb@ubuntu:~$ echo '$USER'
$USER
zbb@ubuntu:~$ echo "$USER"
zbb

1.3 shell中的特殊符号

~ :	家目录
! : 执行历史命令 !!执行上一次命令
$ : 变量中取内容符
+ — * / % : 加减乘除取余
& : 后台运行
* : 星号是shell中的通配符, 匹配所有
? : 问号是shell中的通配符,匹配除回车以外的一个字符
; : 分号可以在shell中一行执行多个命令,命令之间用分号分隔
| : 管道符,上一个命令的输出作为下一个命令的输入 cat filename | grep "root"
\ : 转义字符
``: 反引号 命令中执行命令 echo "DATE IS: `date +%F`"
'': 单引号,版本中字符串要用单引号引起来, 但是不同于双引号的是,单引号不能解析变量
"": 双引号,版本中出现的字符串可以用双引号引起来

1.4 安装Nginx的脚本

#chmod 700 nginx_install.sh
#!/bin/bash
#Author: binbin_erices
#Created Time: 2020/2/22
#Release: 1.0
#Script Description: nginx  install script
yum -y install wget gcc pcre-devel zlib-devel 
wget http://nginx.org/download/nginx-1.16.0.tar.gz
tar xf nginx-1.16.0.tar.gz
cd nginx-1.16.0
./configure --prefix=/usr/local/nginx
make -j 4
make install

1.5 shell中的管道运用

上一个命令的输出作为下一个命令的输入 cat filename | grep “name”

zbb@ubuntu:~$ cat /etc/passwd | grep "zbb"
zbb:x:1000:1000:MyUbuntu,,,:/home/zbb:/bin/bash

1.6 shell重定向

>  重定向输入 覆盖原始数据
>> 重定向追加输入,在原始数据的末尾添加
<  重定向输出 wc -l < /etc/passwd
<< 重定向追加输出 
zbb@ubuntu:~$ echo "123" >> Test.txt
zbb@ubuntu:~$ echo "123" >> Test.txt
zbb@ubuntu:~$ echo "123" >> Test.txt
zbb@ubuntu:~$ cat Test.txt 
123
123
123
zbb@ubuntu:~$ wc < Test.txt 
 3  3 12   #3行 3个单词 12字节
zbb@ubuntu:~$ echo "12345" >> Test.txt
zbb@ubuntu:~$ wc < Test.txt 
 4  4 18
#!/bin/bash
#Author: binbin_erices
#Created Time: 2020/2/22
#Release: 1.0
#Script Description: harddisk partition script
fdisk /dev/sdb << EOF
n
p
3

+512M
W
EOF

EOF也可以用END替换

1.7 shell数学运算

zbb@ubuntu:~$ expr 1+2
1+2
zbb@ubuntu:~$ expr 1 + 2
3
zbb@ubuntu:~$ expr 1 - 2
-1
zbb@ubuntu:~$ expr 1 * 2
expr: 语法错误
zbb@ubuntu:~$ expr 3 \* 2
6
zbb@ubuntu:~$ expr 3 / 2
1
zbb@ubuntu:~$ expr 3 / 1
3
zbb@ubuntu:~$ expr 3 % 4
3
zbb@ubuntu:~$ expr 7 + 1 &>/dev/null ; echo $?
0
zbb@ubuntu:~$ expr 7 +1 &>/dev/null ; echo $?
2
zbb@ubuntu:~$ echo "scale=2; 1436*100/1982"|bc
72.45
zbb@ubuntu:~$ echo "`echo "scale=2; 1436*100/1982"|bc`%"
72.45%

echo &? 命令执行成功返回0, 否者返回错误码

$[] $(())表达式

$[] $(())表达式
[root@station mnt]# echo $[a+2]
6
[root@station mnt]# echo $[a-2]
2
[root@station mnt]# echo $[a*2]
8
[root@station mnt]# echo $[a/2]
2
[root@station mnt]# echo $[a%2]
0
[root@station mnt]# echo $((a+2))
6
[root@station mnt]# echo $((a-2))
2

1.8 整型变量自增

1. i=`expr $i + 1`;
2. let i+=1;
3. ((i++));
4. i=$[$i+1];
5. i=$(( $i + 1 ))

可以实践一下,简单的实例如下:

#!/bin/bash
i=0;
while [ $i -lt 4 ];
do
   echo $i;
   i=`expr $i + 1`;
   # let i+=1;
   # ((i++));
   # i=$[$i+1];
   # i=$(( $i + 1 ))
done

# 对于固定次数的循环,可以通过seq命令来实现,就不需要变量的自增:
for j in $(seq 1 5)
do
  echo $j
done

0x02 shell格式化输出

2.1 echo命令

将内容输出到默认显示设备

语法: echo [-ne] [字符串]

命令选项:
-n 不要再最后加自动换行
-e 若字符串中出现以下字符,则特别加以处理,而不会将它当做一般文字输出

转义字符
\a发出警告声
\b删除前一个字符
\c最后不加上换行符号
\f换行但光标仍旧是停留在原来的位置
\n换行且光标移到行首
\r光标移动到行首 不换行
\t插入TAB
\v与\f相同
#\b必须在一行才可以删除前一个字符
zbb@ubuntu:~$ echo -e "ans\b"
ans
zbb@ubuntu:~$ echo -e -n "ans\b"
anzbb@ubuntu:~$ 
#!/bin/bash

for time in  `seq 9 -1 0`;do
    echo -n -e "\b$time"
    sleep 1
done
echo

2.2 颜色代码

脚本中echo显示内容带颜色显示,echo显示带颜色需要带参数-e

格式:

echo -e “\033[文字背景颜色; 文字颜色m字符串\033[0m”

WARNING:文字背景颜色; 文字颜色之间不带空格

echo -e “\033[41; 36m hello world \033[0m”

其中41的位置代表底色,36位置代表字的颜色

  1. 字背景颜色与文字颜色之间是英文“ ;”
  2. 文字背景色后面有个m
  3. 字符串前后可以没有空格,如果有的话,输出也是同样有空格

0x03 shell基本输入

3.1 read命令

默认接受键盘的输入,回车表示输入结束

read命令选项
-p 打印信息
-t 限定时间
-s 不回显
-n 输入字符个数
#!/bin/bash

clear
echo -n -e "Login: "
read acc
echo -n -e  "PassWord: "
read -s -t10 -n6 pass
echo

echo -e "accont: $acc\tPassword: $pass"

#!/bin/bash

clear
read -p "Login: " acc
echo -n -e "PassWord: "
read -s -t10 -n6 pass

echo -e "accont: $acc\tPassword: $pass"

0x04 shell变量

4.1 变量分类

本地变量:用户私有变量,只有本用户可以使用,保存在家目录下的 .bash_profile(.profile) .bashrc文件中

全局变量:所有用户都可以使用,保存在/etc/profile, /etc/bashrc文件中

用户自定义变量:用户自定义,比如脚本中的变量

全局变量是在用户登录之前加载进内存,本地变量登录成功后加载进内存

4.2 定义变量

(1)变量格式:变量名=值

在shell编程中的变量名和等号之间不能有空格

变量命名规则:
命名只能使用英文字符 数字和下划线 首字符不能以数字开头
中间不能有空格 可以使用下划线
不能使用标点符号
不能使用bash里的关键字(可以用help命令查看保留关键字)
VAR1=18
AGE=24
SCORE_1=100.5
NAME='shell'
字符串要用单引号或者双引号引起来

(2)读取变量内容
读取变量内容符号:$
读取方法: $变量名

(3)取消变量

unset NAME
echo $NAME

(4)定义全局变量export
export NAME=“erices”
上述设置的变量其实都是一次性变量,系统重启就会丢弃
如果希望本地变量或者全局变量可以永久使用,可以将需要设置的变量写入变量文件中即可

(5)定义永久变量

本地变量:用户私有变量,只有本用户可以使用,保存在家目录下的 .bash_profile .bashrc文件中
全局变量:所有用户都可以使用,保存在/etc/profile, /etc/bashrc文件中
export AGE=15 写入到~/.bashrc中就是永久变量

0x05 shell数组

5.1 基本数组

数组语法:

数组名称=(元素1 元素2 … 元素n)

数组读出

${数组名称[索引]}

索引从0开始

数组赋值

#一次赋一个数值

array[0]=“000”

array[1]=“111”

array[2]=“2222”

#一次赋多个数值

array2=(‘111’ ‘222’ ‘333’)

array3=(cat /etc/passwd) 希望是将该文件中的每一行作为一个元素赋值给数组array3

array4=(`ls /var/ftp/shell/for`)

array5=(tom jack alice “bash shell”)

查看数组

#查看系统中存在的数组
zbb@ubuntu:~/shell$ declare -a
declare -a BASH_ARGC='()'
declare -a BASH_ARGV='()'
declare -a BASH_LINENO='()'
declare -ar BASH_REMATCH='()'
declare -a BASH_SOURCE='()'
declare -ar BASH_VERSINFO='([0]="4" [1]="3" [2]="48" [3]="1" [4]="release" [5]="x86_64-pc-linux-gnu")'
declare -a DIRSTACK='()'
declare -a FUNCNAME='()'
declare -a GROUPS='()'
declare -a PIPESTATUS='([0]="0")'

访问数组中的元素

echo ${ARRAY[0]} 访问数组中的第一个元素
echo ${ARRAY[@]} 访问数组中的所有元素 等同于 echo ${ARRAY[*]}
echo ${#ARRAY[@]} 统计数组中元素的个数
echo ${!ARRAY[@]} 获取数组元素的索引
echo ${ARRAY[@]:1} 从数组下标为1开始遍历
echo ${ATTAY[@]:1:2} 从数组下标1开始,向后遍历两个元素
#!/bin/bash
ARRAY=('111' '2222' '3333' '444')
ARRAY[2]='hello'
echo ${ARRAY[0]}
echo ${ARRAY[1]}
echo ${ARRAY[2]}
echo ${ARRAY[3]}

ARRAY5=(tom jack alice "bash shell")
echo ${ARRAY5[0]}
echo ${ARRAY5[1]}
echo ${ARRAY5[2]}
echo ${ARRAY5[3]}

echo ${ARRAY[@]}
echo ${#ARRAY[@]}
echo ${!ARRAY[@]}
echo ${ARRAY[@]:1}
echo ${ARRAY[@]:1:2}

#执行结果
zbb@ubuntu:~/shell$ bash arr.sh 
111
2222
hello
444
tom
jack
alice
bash shell
111 2222 hello 444
4
0 1 2 3
2222 hello 444
2222 hello

遍历数组

默认数组通过数组的元素个数进行遍历

关联数组可以通过数组元素的索引进行遍历

5.2 关联数组

关联数组可以允许用户自定义数组的索引,这样试用起来更加方便,高效

定义关联数组

申明关联数组变量

declare -A ass_arr

declare -A ass_arr2

关联数组赋值

#一次赋一个数值
数组名称[索引]=变量数值
ass_arr[name]="zhangsan"
arr_arr[age]=20
#一次赋多个数值
ass_arr2=([name]="zhangsan" [age]=20)

查看数组

#declare -A

访问数组中元素

echo ${ass_arr[index2]} 访问数组中的第二个元素
echo ${ass_arr[@]} 访问数组中所有元素 等同于echo ${ass_arr[*]}
echo ${#ass_arr[@]} 获取数组中元素个数
echo ${!ass_arr[@]} 获得数组元素的索引
#!/bin/bash

#声明一个关联数组
declare -A ass_arr
declare -A ass_arr2

ass_arr2=([name]='zhangsan' [age]='20')
ass_arr[name]='zhangsan'
ass_arr[age]='20'

echo ${ass_arr[name]}
echo ${ass_arr2[name]}

echo ${ass_arr[@]}
echo ${#ass_arr[@]}
echo ${!ass_arr[@]}
#执行结果
zbb@ubuntu:~/shell$ bash ass_arr.sh 
zhangsan
zhangsan
zhangsan 20
2
name age

5.3 数组遍历

#!/bin/bash

array=( A B C D 1 2 3 4)

echo "case1.标准的for循环"
#${#array[@]}获取数组长度用于循环
for(( i=0;i<${#array[@]};i++)) 
do 
    echo ${array[i]};
done;

echo "case2.for … in"
echo "case2.1 遍历(不带数组下标)"
for element in ${array[@]}
#也可以写成for element in ${array[*]}
do
    echo $element
done

echo "case2.2 遍历(带数组下标)"
for i in "${!array[@]}";   
do 
    printf "%s\t%s\n" "$i" "${array[$i]}"  
done

echo "case3.While循环法"
i=0  
#当变量(下标)小于数组长度时进入循环体
while [ $i -lt ${#array[@]} ]  
do  
    echo ${array[$i]}  
    #按下标打印数组元素
    let i++  
done

0x06 shell流程控制

6.1 if判断语句

shell中的比较运算

(1)数学比较运算

-eq 等于
-gt 大于
-lt 小于
-ge 大于等于
-le 小于等于
-ne 不等于

#man test 
zbb@ubuntu:~/shell$ test 1 -eq 1; echo $?
0
zbb@ubuntu:~/shell$ test 1 -gt 1; echo $?
1
zbb@ubuntu:~/shell$ test 1 -lt 1; echo $?
1
zbb@ubuntu:~/shell$ test 1 -ge 1; echo $?
0
zbb@ubuntu:~/shell$ test 1 -le 1; echo $?
0
zbb@ubuntu:~/shell$ test 1 -ne 1; echo $?
1
#浮点数的比较,shell对浮点数支持很差,需要进行转换
zbb@ubuntu:~/shell$ test `echo "1.5*10"|bc|cut -d '.' -f1` -gt 20; echo $?
1
#bash -x test.sh -x选项查询debug过程

(2) 字符串比较

注意字符串一定不能忘记使用引号引起
==  等于
!=  不等于
-n  检查字符串的长度是否大于0
-z  检查字符串的长度是否为0

(3)文件比较与检查

-d 检查文件是否存在且为目录
-e 检查文件是否存在
-f 检查文件是否存在 且为文件
-r 检查文件是否存在 且可读
-s 检查文件是否存在 且不为空
-w 检查文件是否存在 且可写
-x 检查文件是否存在 且可执行
-O 检查文件是否存在 且被当前用户拥有
-G 检查文件是否存在 且默认组为当前用户组
file1 -nt file2 检查file1是否比file2新
file1 -ot file2 检查file1是否比file2旧

(4) 逻辑运算

&&||!

(5) 赋值运算

=

a=1,等号前后没有空格,否则会报错

if 语法

单if语句格式:

if [ condition ]
then
    command
fi
#!/bin/bash

if [ ! -d /tmp/abc ]
then 
    mkdir -v /tmp/abc
    echo "Create /tmp/abc"
fi

if-then-else语句

适用范围:两步判,条件为真干什么,条件为假干什么

if [ condition ]
then 
	command1
else
    command2
fi
#!/bin/bash

if [ $USER == "root" ]
then 
    echo "Hello Administrator!"
else
    echo "hello other user!"
fi

if-then-elif语句

适用范围: 多于两个以上的判断结果,也就是多于一个以上的判断条件

if [ condition1 ]
then
    command1
elif [ condition2 ]
then
    command2
...
fi
#!/bin/bash

if [ $1 -eq $2 ]
then
    echo "$1==$1"
elif [ $1 -gt $2 ]
then
    echo "$1 > $2"
else
    echo "$1 < $2"
fi

多条件表示

逻辑与

if [ condition1 -a condition2 ] 
if [ condition1 ] && [ condition2 ]

逻辑或

if [ condition1 -o condition2 ]  
if [ condition1 ] || [ condition2 ]

逻辑非(取反)

    !  

高级应用

if ((100%3+1 > 1))
then
    echo "YES"
else
   echo "NO"
fi

if ((100%3+1 > 1));then
    echo "YES"
else
   echo "NO"
fi

6.2 for循环语句

for语法一
for var in value1 value2 ...
do
	command
done
#!/bin/bash

for i in `seq 10 -1 1`
do
    echo $i
done

#需要使用转义字符,赋值是字符串
for var in zhangsan\'s is school, he is handsome
do
     echo "word:$var"
done
for语法二
for ((变量;条件;自增减运算))
do
    代码块
done
for ((i=1; i < 10; i++))
do
    echo $i
done

#多变量C格式
for (( n=10,m=0;n>0,m<10;n--,m++ ))
do
    echo -e "$n\t$m"
done

#无限循环
for(;;)
do
	echo 'hello'
done

6.3 循环控制语句

sleep N 脚本执行到该步休眠N秒

#!/bin/bash
#监控主机存活的脚本

for ((;;))
do
    ping -c1 $1 &>/dev/null
    if [ $? -eq 0 ]
    then
        echo "`date +"%F %H:%M:%S"`: $1 is up"
    else
        echo "`date +"%F %H:%M:%S"`: $1 is down"
    fi
    # 生产环境中建议1min以上
    sleep 5
done

continue跳过循环中的某次循环

#!/bin/bash


for ((i = 0; i < 10; i++))
do
    if (($i%2 == 0 ))
    then
        continue
    fi
    echo $i
done

for ((i = 0; i < 10; i++))
do
    if [ $(($i%2)) -eq 0 ]
    then
        continue
    fi
    echo $i
done

break跳出循环

#!/bin/bash

for ((;;))
do
    read -p "char: " ch
    if [ $ch == 'Q' ]
    then
        break
    else
        echo "your enter char is: $ch"
    fi
done

break跳出多层循环

有时需要跳出多层循环,使用: break n, n表示需要跳出的循环层数,默认情况下n = 1, 代表只跳出当前循环

#!/bin/bash

for ((i=0; i < 10; i++))
do 
    echo "#OUT LOOP: $i"
    for ((;;))
    do 
        echo "ahhh"
        break 2
    done
done 

6.4 while循环语句

while循环语法

知道循环次数要用for,不知道循环次数用while

while [ condition ]
do 
    command
done 
#!/bin/bash

read -p "Ch: " ch
while [ $ch != "Q" ]
do
    echo "your enter ch is $ch"
    read -p "Ch: " ch
done
#!/bin/bash
i=1
while [ $i -lt 10 ]
do
    for ((j = 1;j <= $i; j++))
    do
        echo -n "$j * $i =$((i*j)) "
    done
    echo
    i=$((i+1))
done

6.5 until语句

和while正好相反, until是条件为假开始执行,条件为真停止执行

until [ condition ]
do
   command
done
#!/bin/bash

num=10
until [ $num -ge 21 ]
do
     echo "num: $num"
     num=$((num+1))
done

6.6 case多条件分支语句

case语法
语法:
case 变量 in
条件1)
  执行代码111
;;
条件2)
  执行代码222
;;
esac
#!/bin/bash

read -p "enter a num: " num
case $num in 
1)
    echo "ahhh"
;;
2) 
    echo "bbbbb"
;;
*)
    echo "byebye"
;;
esac

6.7 shell特殊变量

$*  代表所有参数
$@$*相同
$#: 传入参数个数
$?: 命令执行返回值
$$: 脚本执行的进程号
$n: 第n个传入参数  $0 表示脚本的名称
$_: 最后执行命令

6.8 多行shell语句写在一行

6.8.1 间隔5秒查询tomcat进程是否存在,如果存在跳出循环,最多循环20次,等待100秒

for i in $(seq 1 20); do ps aux| grep tomcat | grep -v grep && break;sleep 5;done

6.8.2 while循环实例

间隔5秒查询tomcat进程是否存在,如果存在跳出循环,如果不存在将一直等待

while true; do ps aux | grep tomcat | grep -v grep && break;sleep 5; done

注意 分号后的空格 可加 可不加,以下代码也是可以正常运行的

while true;do ps aux | grep tomcat | grep -v grep && break;sleep 5;done

0x07 shell函数

7.1 shell函数

函数语法
#语法1
函数名(){
    代码块
    return N
}

#语法2:
function 函数名称() {
	代码块
	return N
}

#语法3:
function 函数名称 {
	代码块
	return N
}
#!/bin/bash

start(){
   echo "func exec ..... [OK]"
   #return 0
}

stop(){
    echo "func stop .... [FAIL]"
}

#call func
start
start
stop
stop

vim /lib/lsb/init-functions ubuntu下的shell函数库
/etc/init.d/functions CentOS下的函数库

0x08 正则表达式

shell支持正则表达式,但不是所有的命令都支持正则表达式。 常见的命令中有grep sed awk等命令支持正则表达式

特殊字符

8.1 定位符

定位符使用技巧: 同时锚定开头和结尾,做精匹配,单一锚定开头和结尾,做模糊匹配

定位符说明
^锚定开头^a 以a开头 默认锚定一个字符
$锚定结尾a$ 以a结尾 默认锚定一个字符
zbb@ubuntu:~/shell$ egrep "^d" monitor.sh 
do
done
zbb@ubuntu:~/shell$ egrep "5$" monitor.sh 
    sleep 5
8.2 匹配符
匹配符说明
.匹配除回车以外的任意字符
()字符串分组
[]定义字符类,匹配括号中的一个字符
[^]表示否定括号中出现字符类中的字符,去反
\转义字符
|管道
egrep "^a[0-9]c$" file
a3c

egrep "^a[^0-9]c$" file
acc
abc
a_c
aZc
a c

egrep "^a\*c$" file
a*c

egrep "^(a|b)c$" file
ac
bc
8.3 限定符
限定符说明
*某个字符之后加星号表示该字符不出现或者出现多次
与星号类似,略有不同,表示该字符出现一次或者不出现
+与星号类似 表示其前面的字符出现一个或者多次 但是必须出现一次
{n, m}某个字符之后出现 表示该字符至少出现n次 最多m次
{m}正好出现m次
egrep "^ab*c$" file
ac
abbbc
abbc
abc
egrep "^ab?c$" file
ac
abc
egrep "^ab+c$" file
abbbc
abbc
abc
egrep "^ab{1,2}c$" file
abbc
abc
8.4 分割字符串
# awk:
echo "1:3:5" | awk -F ":" '{print $NF}'
# sed:
echo "1:3:5" | sed 's/.*:\([^:]*\)$/\1/'
# 输出 5
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Erice_s

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值