Shell 基础知识 Shell 是一个应用程序,它连接了用户和 Linux 内核,让用户能够更加高效、安全、低成本地使用 Linux 内核,这就是 Shell 的本质。然而Shell本身并不是内核的一部分,它只是站在内核的基础上编写的一个应用程序,但是 Shell 也有着它的特殊性,就是开机立马启动,并呈现在用户面前;用户通过 Shell 来使用 Linux,不启动 Shell 的话,用户就没办法使用 Linux
Shell 也是一种脚本,是系统命令的集合,可以使用逻辑判断、循环等语法,可以自定义函数,我们编写完源码后不用编译,直接运行源码即可。
Shell 脚本是在 Linux 的 shell 中运行的,所以称为 shell 脚本。本质上,shell 脚本 就是一些命令的集合。shell 脚本 可以实现自动化运维,所以能帮助我们很方便的管理服务器;比如我们可以指定一个任务计划,定时的去执行某个 shell 脚本 已满足需求。
1. Shell 脚本结构与执行 1.1 脚本结构 第一行一定得是 #!/bin/bash
。该命令说明,该文件使用的是 bash 语法,如果不设置改行,则该脚本不会被执行。以 #
开头的行作为解释说明。Shell 脚本 通常以 sh
为后缀,用于区分这是一个 Shell 脚本。
下面我们来编写一个 shell 脚本,如下所示:
1 2 3 4 5 6 7 8 9 $ mkdir shell$ cd shell$ vi 1.sh # 然后写入以下内容 # !/bin/bash touch /tmp/1.txt chmod 600 /tmp/2.txt mv /tmp/1.txt /tmp/2.txt
SHELL
1.1
1.2 脚本执行 接下来我们执行刚才编写的脚本
其实 shell 脚本 还有一种执行方法,但前提是脚本本身要有执行权限,所以执行前我们需要给脚本加一个 x
权限
1 2 3 4 $ ./1.sh -bash: ./1.sh: 权限不够 $ chmod +x 1.sh $ ./1.sh
BASH
1.2
2. 常用命令 2.1 查看脚本执行过程1 2 3 4 $ bash -x 1.sh + touch /tmp/1.txt + chmod 600 /tmp/2.txt + mv /tmp/1.txt /tmp/2.txt
BASH
2.1
2.2 查看脚本是否有语法错误
2.3 date 命令 2.3.1 显示 年 月 日1 2 3 date +%Y-%m-%d date +%y-%m-%d date +%F
BASH
2.3.1
2.3.2 显示 小时 分钟 秒1 2 date +%H:%M:%Sdate +%T
BASH
2.3.2
2.3.3 显示星期
2.3.3
2.3.4 时间戳 时间戳是指特定时间的标识,通常以数字形式表示,表示自某个特定时刻以来经过的时间。时间戳广泛用于计算机系统、数据库和网络应用中,以记录事件的发生时间或用于时间相关的计算
这里使用的是 Unix 时间戳
Unix 时间戳 :自 1970 年 1 月 1 日(UTC)以来经过的秒数。例如,Unix 时间戳 1633072800
表示 2021 年 10 月 1 日,要是看现在的就用下面的命令
使用下面的命令显示输入秒数之前的时间
2.3.4
2.3.5 显示一个小时之前/之后1 2 date -d "+1 hour" date -d "-1 hour"
BASH
2.3.5
2.3.6 显示一天之前/之后1 2 date -d "+1 day" date -d "-1 day"
BASH
2.3.6
3. shell 脚本中的变量 在 shell 脚本 中使用变量可以节省时间并且使我们的脚本更加专业,所以当我们编写一个脚本时,就可以使用变量来代替某个使用频繁并且长度很长的字符串。变量的格式:”变量名=变量的值”
3.1 引用命令的结果 当我们引用某个命令的结果时,可以使用变量代替
1 2 3 4 5 6 $ a=`date +%w` $ echo $a 6 $ a=$(date +%w) $ echo $a 6
BASH
3.1
3.2 与用户交互1 2 3 4 5 6 7 8 $ read -p "请输入一个数字:" n 请输入一个数字:10 $ echo $n 10 $ read -p "请输入一个数字:" 请输入一个数字:2005 $ echo $REPLY 2005
BASH
3.2
3.3 内置变量1 2 3 4 5 6 7 8 9 $ vi bian.sh echo "\$1=$1 " echo "第二个参数是$2 " echo "第三个参数是$3 " echo "本脚本一共有$# 个参数" echo "\$0是$0 "
BASH
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 $ sh bian.sh$1 = 第二个参数是 第三个参数是 本脚本一共有0个参数$0 是bian.sh $ sh bian.sh a b c$1 =a 第二个参数是b 第三个参数是c 本脚本一共有3个参数$0 是bian.sh
BASH
3.3
3.4 数学运算1 2 3 4 5 6 7 8 $ vi sum.sh a=1 b=2sum =$[$a +$b ]echo "$a +$b =$sum "
BASH
3.4
4. Shell 中的逻辑判断 4.1 不带有 else 基础结构
1 2 3 4 if [判断语句] then command fi
BASH
example
1 2 3 4 5 6 7 8 9 10 $ vi if1.sh a=10if [ $a -gt 4 ]then echo okfi
BASH
1 2 3 4 5 6 7 8 9 $ sh -x if1.sh + a=10 + '[' 10 -gt 4 ']' + echo ok ok $ sh -n if1.sh
BASH
4.1
4.2 带有 else 基础结构
1 2 3 4 5 6 if [判断语句] then command else command fi
BASH
exapmle
1 2 3 4 5 6 7 8 9 10 11 $ vi if2.sh a=10if [ $a -gt 4 ] then echo ok else echo "not ok"
BASH
1 2 3 4 5 6 7 8 9 10 $ sh -x if1.sh sh -x if1.sh + a=10 + '[' 10 -gt 4 ']' + echo ok ok $ sh -n if1.sh
BASH
4.1.2
4.3 带有 elif1 2 3 4 5 6 7 8 9 10 11 12 13 14 $ vi if3.sh a=3if [ $a -gt 4 ] then echo ok elif [ $a -gt 8 ] then echo "very ok" else echo "not ok" fi
BASH
1 2 3 4 5 6 7 $ sh -x if3.sh + a=3 + '[' 3 -gt 4 ']' + '[' 3 -gt 8 ']' + echo 'not ok' not ok
BASH
4.3
4.4 嵌套1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 $ vi if4.sh a=10if [ $a -gt 4 ]then if [ $a -lt 20 ] then echo "ok" else echo "very ok" fi else echo "not ok" fi
BASH
4.4
4.5 多个条件1 2 if [ $a -gt 5 ] && [ $a -lt 10 ] == if [ $a -gt 5 -a $a -lt 10] if [ $b -gt 5 ] || [ $b -lt 3] == if [ $b -gt 5 -o $b -lt 3 ]
BASH
4.6 if 逻辑判断 4.6.1 if 判断文件的目录属性 shell 脚本 中 if 经常用于判断文档的属性,比如判断是普通文件还是目录,判断文件是否有读、写、执行权限等。if 常用选项如下:
-e
:判断文件或目录是否存在。
-d
:判断是不是目录以及是否存在。
-f
:判断是不是普通文件以及是否存在。
-T
:判断是否有读权限。
-w
:判断是否有写权限。
-X
:判断是否可执行。
注:*root用户对文件的读写比较特殊,即使一个文件没有给root用户读或者写的权限,root也可以读或者写
4.6.2 if 判断的一些特殊用法
命令 if [ -z "$a" ];
表示当变量 a 的值为空时会怎么样
命令 if [ -n "$a" ];
表示当变量 a 的值不为空时会怎么样
命令 if grep -q '123' 1.sh; then
表示如果 1.sh 中含有 ‘123’ 会怎么样,其中 -q
表示即使过滤内容也不要打印出来
if (($a<1)); then
等同于 if [ $a -lt 1 ]; then
,二者都可以用来进行判断,需要注意的是,当我们未对变量 a 进行赋值时则会报错
注意 :[ ]
中不能使用<
, >
, ==
, !=
, >=
, <=
这样的符号,需要时要使用固定写法 -gt (>)
; -lt(<)
; -ge(>=)
; -le(<=)
; -eq(==)
; -ne(!=)
4.7 shell 中的 case 判断 case 判断的基础格式
1 2 3 4 5 6 7 8 9 10 11 case 变量 in value1) command ;; value2) command ;; *) command ;;esac
BASH
为了让我们能够更加清晰的理解 case 逻辑判断,接下来我们编写一个脚本来进行实验
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 $ vi case.shread -p "Please input a number:" n if [ -z "$n " ]then echo "Please input a number." exit 1 fi n1=`echo $n |sed 's/[0-9]//g' `if [ -n "$n1 " ]then echo "Please input a number." exit 1 fi if [ $n -lt 60 ] && [ $n -ge 0 ] then tag=1elif [ $n -ge 60 ] && [ $n -lt 80 ] then tag=2elif [ $n -ge 80 ] && [ $n -lt 90 ] then tag=3elif [ $n -ge 90 ] && [ $n -le 100 ] then tag=4 else tag=0 fi case $tag in 1) echo "not ok" ;; 2) echo "ok" ;; 3) echo "very ok" ;; 4) echo "oook" ;; *) echo "The number range is 0-100." ;;esac
BASH
这段的意思是:接收用户输入的一个数字,并根据该数字的范围(0-100),输出相应的评价信息,如 “not ok”、”ok”、”very ok” 或 “oook”,如果输入超出范围或不是数字,则提示错误
4.7
5. shell 中的循环 5.1 for 循环 基础结构如下
1 2 3 4 for 变量名 in 循环条件;do command done
BASH
下面进行一个简单的演示
1 2 3 4 5 6 7 8 9 10 11 $ vi for1.shsum =0for i in `seq 1 10`do sum =$[$sum +$i ] echo $i done echo $sum
BASH
5.1
5.2 while 循环 基础结构
1 2 3 4 while 条件do command done
BASH
example 1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 $ vi while2.shwhile :do read -p "Please input a number: " n if [ -z "$n " ] then echo "you need input sth." continue fi n1=`echo $n |sed 's/[0-9]//g ' ` if [ -n "$n1 " ] then echo "you just only input numbers." continue fi break done echo $n
BASH
5.2
6. Shell 中的中断与继续 6.1 跳出循环 break
在脚本中表设计跳出该层循环
1 2 3 4 5 6 7 8 9 10 11 12 13 14 $ vi break1.shfor i in `seq 1 5`do echo $i if [ $i -eq 3 ] then break fi echo $i done echo aaaaa
BASH
6.1
6.2 结束本次循环 当在 shell 脚本中使用 continue 时,结束的不是整个循环,而是本次循环。忽略 continue 之下的代码,直接进行下一次循环
1 2 3 4 5 6 7 8 9 10 11 12 13 14 $ vi continue1.shfor i in `seq 1 5`do echo $i if [ $i == 3 ] then continue fi echo $i done echo $i
BASH
6.2
6.3 退出整个脚本 当我们在 shell 脚本中遇到 exit 是,其表示直接退出整个 shell 脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 $ vi exit1.shfor i in `seq 1 5`do echo $i if [ $i == 3 ] then exit fi echo $i done echo aaaa
BASH
6.3
7. Shell 中的函数 shell 脚本 中的函数就是先把一段代码整理到了一个小单元中,并给这个小单元命名,当我们用到这段代码时直接调用这个小单元的名字就可以了,这样很方便,省时省力。但我们需要注意,在 shell 脚本 中,函数一定要写在前面 ,因为函数要被调用的,如果还未出现就被调用就会出错。
基础格式
1 2 3 4 function f_name () { command }
BASH
解释:
function
是定义一个函数的关键字,但在大多数现代 Shell(如 Bash)中,function
关键字是可选的
f_name
是函数的名称(你可以自定义这个名字),它可以是任何合法的函数名
{}
大括号包围的是函数体,里面的 command
表示函数中要执行的命令
7.1 打印出第一个、第二个参数、参数的个数及脚本名1 2 3 4 5 6 7 8 9 $ vi fun1.shinput () { echo $1 $2 $# $0 } input 1 a b
BASH
7.1
7.2 加法的函数1 2 3 4 5 6 7 8 9 10 $ vi fun2.shsum () { s=$[$1 +$2 ] echo $s }sum 1 2
BASH
7.2
7.3 获得一个网卡的 IP 地址1 2 3 4 5 6 7 8 9 10 11 $ vi fun3.ship () { ifconfig | grep -A1 "$1 : " | tail -1 | awk '{print $2}' }read -p "Please input the eth name:" e myip=`ip $e `echo "$e address is $myip "
BASH
7.3
8. shell 中的数组 8.1 数组读取 首先我们需要先定义一个数组 a=(1 2 3 4 5)
命令 echo ${a[@]}
读取数组中的全部元素
命令 echo ${#a[@]}
获取数组的元素个数
命令 echo ${a[2]}
读取第三个元素,数组从 0 开始
命令 echo ${a[*]}
等同于 echo ${a[@]}
作用为显示整个数组
8.2 数组赋值
a[1]=100; echo ${a[@]}
替换指定元素值
a[5]=2; echo ${a[@]}
如果下标不存在则会自动添加一个元素
a[7]=6; echo ${a[@]}
跳着添加元素时,中间未赋值的元素,不显示且无值
8.3 数组的删除
命令 unset a[1]
用于删除单个元素
命令 unset a
用于删除整个数组
8.4 数组分片 在进行实验操作之前,需要对一个数组进行赋值 a=($(seq 1 5))
命令 echo ${a[@]:0:3}
表示从第一个元素开始,截取 3 个元素,并打印出来
命令 echo ${a[@]:1:4}
表示从第二个元素开始,截取 4 个元素,并打印出来
命令 echo ${a[@]:0-3:2}
表示从倒数第 3 个元素开始,截取 2 个元素,并打印出来
8.5 数组替换
命令 echo ${a[@]/b/100}
表示用 100 替换 b,但不会保存替换,只是打印出来
命令 a=(${a[@]/b/100})
表示用 100 替换 b,这种方法不仅可以打印出来,还可以保存替换