Shell 基础知识

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.2 脚本执行

​ 接下来我们执行刚才编写的脚本

1
$ bash 1.sh
BASH

​ 其实 shell 脚本 还有一种执行方法,但前提是脚本本身要有执行权限,所以执行前我们需要给脚本加一个 x 权限

1
2
3
4
$ ./1.sh
-bash: ./1.sh: 权限不够
$ chmod +x 1.sh
$ ./1.sh
BASH

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.2 查看脚本是否有语法错误

1
$ bash -n 1.sh
BASH

2.3 date 命令

2.3.1 显示 年 月 日
1
2
3
date +%Y-%m-%d #年(四位)月日
date +%y-%m-%d #年(两位)月日
date +%F #年(四位)月日
BASH

2.3.2 显示 小时 分钟 秒
1
2
date +%H:%M:%S
date +%T
BASH

2.3.3 显示星期
1
2
date +%w #一周中的第X天
date +%W #一年中的第X周
BASH

2.3.4 时间戳

​ 时间戳是指特定时间的标识,通常以数字形式表示,表示自某个特定时刻以来经过的时间。时间戳广泛用于计算机系统、数据库和网络应用中,以记录事件的发生时间或用于时间相关的计算

​ 这里使用的是 Unix 时间戳

Unix 时间戳:自 1970 年 1 月 1 日(UTC)以来经过的秒数。例如,Unix 时间戳 1633072800 表示 2021 年 10 月 1 日,要是看现在的就用下面的命令

1
date +%s
BASH

​ 使用下面的命令显示输入秒数之前的时间

1
date -d @1633072800
BASH

2.3.5 显示一个小时之前/之后
1
2
date -d "+1 hour" #1h之后
date -d "-1 hour" #1h之前
BASH

2.3.6 显示一天之前/之后
1
2
date -d "+1 day" #一天后
date -d "-1 day" #一天前
BASH

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.2 与用户交互

1
2
3
4
5
6
7
8
$ read -p "请输入一个数字:" n
请输入一个数字:10
$ echo $n
10
$ read -p "请输入一个数字:"
请输入一个数字:2005
$ echo $REPLY
2005
BASH

3.3 内置变量

1
2
3
4
5
6
7
8
9
$ vi bian.sh #创建一个名为 bian.sh 的脚本
# 填入以下内容

#!/bin/bash
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.4 数学运算

1
2
3
4
5
6
7
8
$ vi sum.sh
# 填入以下内容

#!/bin/bash
a=1
b=2
sum=$[$a+$b]
echo "$a+$b=$sum"
BASH
1
2
3
# 执行脚本
$ sh sum.sh
1+2=3
BASH

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
# 填入以下内容

#!/bin/bash

a=10
if [ $a -gt 4 ]
then
echo ok
fi
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.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
# 填入以下内容

#!/bin/bash

a=10
if [ $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.3 带有 elif

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ vi if3.sh
# 填入以下内容

#!/bin/bash
a=3
if [ $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.4 嵌套

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ vi if4.sh
# 填入以下内容

#!/bin/bash

a=10
if [ $a -gt 4 ]
then
if [ $a -lt 20 ]
then
echo "ok"
else
echo "very ok"
fi
else
echo "not ok"
fi
BASH

4.5 多个条件

1
2
if [ $a -gt 5 ] && [ $a -lt 10 ] == if [ $a -gt 5 -a $a -lt 10]     # -a表示 and
if [ $b -gt 5 ] || [ $b -lt 3] == if [ $b -gt 5 -o $b -lt 3 ] # -o表示 or
BASH

4.6 if 逻辑判断

4.6.1 if 判断文件的目录属性

​ shell 脚本 中 if 经常用于判断文档的属性,比如判断是普通文件还是目录,判断文件是否有读、写、执行权限等。if 常用选项如下:

  • -e:判断文件或目录是否存在。
  • -d:判断是不是目录以及是否存在。
  • -f:判断是不是普通文件以及是否存在。
  • -T:判断是否有读权限。
  • -w:判断是否有写权限。
  • -X:判断是否可执行。

注:*root用户对文件的读写比较特殊,即使一个文件没有给root用户读或者写的权限,root也可以读或者写

4.6.2 if 判断的一些特殊用法
  1. 命令 if [ -z "$a" ]; 表示当变量 a 的值为空时会怎么样

  2. 命令 if [ -n "$a" ]; 表示当变量 a 的值不为空时会怎么样

  3. 命令 if grep -q '123' 1.sh; then 表示如果 1.sh 中含有 ‘123’ 会怎么样,其中 -q 表示即使过滤内容也不要打印出来

  4. 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.sh
# 填入以下内容

#!/bin/bash
read -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 ] # 条件是 0 <= n < 60
then
tag=1
elif [ $n -ge 60 ] && [ $n -lt 80 ] # 条件是 60 <= n < 80
then
tag=2
elif [ $n -ge 80 ] && [ $n -lt 90 ] # 条件是 80 <= n < 90
then
tag=3
elif [ $n -ge 90 ] && [ $n -le 100 ] # 条件是 90 <= n <= 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”,如果输入超出范围或不是数字,则提示错误

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.sh
# 填入以下内容

#!/bin/bash
sum=0
for i in `seq 1 10`
do
sum=$[$sum+$i]
echo $i
done
echo $sum
BASH

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.sh
# 填入以下内容

#!/bin/bash
while :
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

6. Shell 中的中断与继续

6.1 跳出循环

break 在脚本中表设计跳出该层循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ vi break1.sh
# 填入以下内容

#!/bin/bash
for i in `seq 1 5`
do
echo $i
if [ $i -eq 3 ]
then
break
fi
echo $i
done
echo aaaaa
BASH

6.2 结束本次循环

​ 当在 shell 脚本中使用 continue 时,结束的不是整个循环,而是本次循环。忽略 continue 之下的代码,直接进行下一次循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ vi continue1.sh
# 填入以下内容

#!/bin/bash
for i in `seq 1 5`
do
echo $i
if [ $i == 3 ]
then
continue ##此处continue表示若 $i == 3 则结束本次循环
fi
echo $i
done
echo $i
BASH

6.3 退出整个脚本

​ 当我们在 shell 脚本中遇到 exit 是,其表示直接退出整个 shell 脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ vi exit1.sh
# 填入以下内容

#!/bin/bash
for i in `seq 1 5`
do
echo $i
if [ $i == 3 ]
then
exit
fi
echo $i
done
echo aaaa
BASH

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.sh
# 填入以下内容

#!/bin/bash
input()
{
echo $1 $2 $# $0 # 函数的参数:$1 $2 $# ;$0则是脚本的名字
}
input 1 a b
BASH

7.2 加法的函数

1
2
3
4
5
6
7
8
9
10
$ vi fun2.sh
# 填入以下内容

#!/bin/bash
sum()
{
s=$[$1+$2]
echo $s
}
sum 1 2
BASH

7.3 获得一个网卡的 IP 地址

1
2
3
4
5
6
7
8
9
10
11
$ vi fun3.sh
# 填入以下内容

#!/bin/bash
ip()
{
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

8. shell 中的数组

8.1 数组读取

​ 首先我们需要先定义一个数组 a=(1 2 3 4 5)

  1. 命令 echo ${a[@]} 读取数组中的全部元素

  2. 命令 echo ${#a[@]} 获取数组的元素个数

  3. 命令 echo ${a[2]} 读取第三个元素,数组从 0 开始

  4. 命令 echo ${a[*]} 等同于 echo ${a[@]} 作用为显示整个数组

8.2 数组赋值

  1. a[1]=100; echo ${a[@]} 替换指定元素值

  2. a[5]=2; echo ${a[@]} 如果下标不存在则会自动添加一个元素

  3. a[7]=6; echo ${a[@]} 跳着添加元素时,中间未赋值的元素,不显示且无值

8.3 数组的删除

  1. 命令 unset a[1] 用于删除单个元素

  2. 命令 unset a 用于删除整个数组

8.4 数组分片

​ 在进行实验操作之前,需要对一个数组进行赋值 a=($(seq 1 5))

  1. 命令 echo ${a[@]:0:3} 表示从第一个元素开始,截取 3 个元素,并打印出来

  2. 命令 echo ${a[@]:1:4} 表示从第二个元素开始,截取 4 个元素,并打印出来

  3. 命令 echo ${a[@]:0-3:2} 表示从倒数第 3 个元素开始,截取 2 个元素,并打印出来

8.5 数组替换

  1. 命令 echo ${a[@]/b/100} 表示用 100 替换 b,但不会保存替换,只是打印出来

  2. 命令 a=(${a[@]/b/100}) 表示用 100 替换 b,这种方法不仅可以打印出来,还可以保存替换


Shell 基础知识
https://moka.anitsuri.top/2024/09/28/shell_Basic/
作者
アニつり
发布于
2024年9月28日
许可协议