Shell脚本保姆级教程

Posted 汤米先生

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Shell脚本保姆级教程相关的知识,希望对你有一定的参考价值。

文章目录


前言

总结了一下Shell脚本的基础知识,都结合了示例,通俗易懂。

一. Shell基础

shell是命令解释器的一个总称

计算机是由计算机硬件组成的,但是人类无法直接使用硬件,于是就产生了操作系统内核来控制计算机硬件,但是操作系统内核也不能被人们直接操作,例如我们所熟知的window系统和Linux系统,这些就是通过用户应用程序来控制系统内核的,众所周知计算机只能识别0和1,而命令解释器就是用来将人类自然语言转化为计算机能识别语言(0和1)的媒介,当然,不同的命令也有不同的解释器,常见的解释器有:

  1. /bin/bash (常用的)
  2. /bin/sh
  3. /bin/csh
  4. /bin/tcsh

解释器负责将用户的指令翻译为内核可以识别的指令。
通过usermod,chsh可以更改登录Shell。
下面说一下关于解释器的一些操作

1. 查看

我们可以 输入 cat /etc/shells查看我们拥有那些解释器

2. 安装

我们可以通过输入 yum -y install xxx安装我们想要的解释器、

3. 使用

我们可以通过输入 usermod -s 解释器名字 用户名 来使用这个解释器

然后输入 grep 用户名 /etc/passwd 来查看当前正在使用的解释器

也可以使用 chsh -s 解释器名字 用户名 将解释器修改回来

4. Bash基本特性

Bash的作为默认的解释器自然有他的道理,下面就来解释一下,Bash解释器的一些特别之处。

Bash解释器具有许多方便的快捷键

  1. Ctrl + a :移到命令行首
  2. Ctrl + e :移到命令行尾
  3. Ctrl + r:逆向搜索命令历史
  4. Ctrl + l:清屏
  5. Ctrl + o:执行当前命令,并选择上一条命令
  6. Ctrl + s:阻止屏幕输出
  7. Ctrl + q:允许屏幕输出
  8. Ctrl + c:终止命令,将我们当前执行的命令撤销掉
  9. Ctrl + z:挂起命令
  10. Ctrl + g:从历史搜索模式退出
  11. Ctrl + f :按字符前移(右向)
  12. Ctrl + b :按字符后移(左向)
  13. Alt + f :按单词前移(右向)
  14. Alt + b :按单词后移(左向)
  15. Ctrl + xx:在命令行首和光标之间移动
  16. Ctrl + u :从光标处删除至命令行首
  17. Ctrl + k :从光标处删除至命令行尾
  18. Ctrl + w :从光标处删除至字首
  19. Alt + d :从光标处删除至字尾
  20. Ctrl + d :删除光标处的字符
  21. Ctrl + h :删除光标前的字符
  22. Ctrl + y :粘贴至光标后
  23. Alt + c :从光标处更改为首字母大写的单词
  24. Alt + u :从光标处更改为全部大写的单词
  25. Alt + l :从光标处更改为全部小写的单词
  26. Ctrl + t :交换光标处和之前的字符
  27. Alt + t :交换光标处和之前的单词
  28. Alt + Backspace:与 Ctrl + w 相同类似
  29. 还有 Tab 快速补全代码快捷键,可以大大的减少我们的代码编辑量

查看历史命令

可用通过上下键来查看使用过的命令记录,对于一些的重复的命令我们就不必再去敲一遍了。

命令别名

有些命令具有别名 比如 ll = ls -l
也就是给一个命令又起了个名字,简写了,我们也可以自己创建别名,来提高编辑代码的速率。

标准输入输出的重定向

把输出不显示到屏幕上而显示到文件中
使用 `>` 将输出显示在文件中,同时 `>` 也意味着**覆盖**文件中以前的内容,使用 `>>` 才是在原内容上**追加**的意思



并不是所以的输出信息都可以用 >或者>>添加到文件中,以上正常的输出可以,但是错误的输出 就不行了

我们可以用 2>来将错误的输出添加到文件中

但如果又有错误又有正常输出信息呢?我们该如何把他们存放到文件中?
我们可以使用 &> 将他们一块儿存入文件中,同样的一个 > 都是覆盖,>> 是追加

管道

管道可以联合多条命令,将第一条命令的结果给第二条命令使用
比如我们来实行一下 过滤操作 ,从yum 列表中筛选出含有 bash 的软件

yum list | grep bash

二. hello world

我们还是先从创建第一个 hello world 开始
首先创建一个脚本:文件
shell/day1 是我提前创建好的目录

vim /root/shell/day1/first.sh

按s 插入Shell命令

echo  "hello world -tom"

按Esc 输入 :x保存并退出

然后给脚本添加可执行权限

chmod +x /root/shell/day1/first.sh

下一步 就可以执行这个脚本了

vim /root/shell/day1/first.sh


在上面步骤中有关键的一步 ,就是给脚本文件可执行权限 ,其实有一种方法,可以不用给权限还能运行脚本
在不具有可执行权限时,我们可以用下面方法执行脚本

  1. 解释器 脚本文件名 例如 :bash first.sh
  2. source 脚本文件名 这种方法不会启动子进程,我们可以通过 pstree(需要下载)查看进程树来观察不同。

三. 变量

1. 自定义变量

定义变量

变量名=变量值

取消变量

unset 变量名

变量规范

  1. 变量 = 两边不能加空格,不能使用关键字做变量名,如ls,cd等等。
  2. 如果变量名已经存在则覆盖以前的变量名 。
  3. 变量名称只能由字母数字下划线组成,而且不能以数字开头。
  4. 在打印一个变量的时候,最好用括起来

2. 环境变量

变量名为大写,由操作系统维护 ,这些都是系统提前设置好的变量

  1. 存储在/etc/profile或~/.bash_profile中
  2. 命令env可以列出所有的环境变量
  3. 常见的环境变量有:PATH,PWD,USER,UID,HOME,SHELL
    PATH:命令搜索变量,负责搜索命令是否存在
    PWD:显示当前所在路径的变量
    USER:显示当前用户名
    UID:显示当前用户的ID号
    HOME:当前用户的家目录
    SHELL:显示当前正在使用的解释器

3. 位置变量

bash内置变量 ,存储脚本执行时的参数
使用$n表示,n为数字序列号,如果n<10用 $n表示 ,如果n>10,用 $n表示
下面就来演示一下位置变量的使用方法:
先创建一个脚本文件

vim /root/shell/day1/a.sh

然后在脚本文件中设置 三个位置变量

echo $1
echo $2
echo $3


然后再给文件 可执行 权限

chmod +x /root/shell/day1/a.sh

最后 给位置变量赋值,再执行脚本文件

/root/shell/day1/a.sh aa bb cc

第一个位置变量 aa , 第二个位置变量 bb,第三个位置变量cc

4. 预定义变量

bash内置变量,可以调用,但不能赋值和修改,用来保存脚本程序的执行信息。

变量名含义
$0当前所在的进程或脚本名
$$当前运行进程的PID号
$?命令执行后的返回状态,0表示正常,1或其他值表示异常,只针对上一条命令
$#以加载的位置变量的个数
$*所有位置变量的值

下面是$?用法和其余几个的用法

错误显示非0,正常显示0

后面aa bb cc dd是4个位置变量的值

5. 单引号和双引号的区别

下面来举个例子

可以看出 "" 可以识别特殊符号 而 ' ' 不能识别特殊符号
其中还有 `` 反引号 与 $() 等效 ,引号和括号内都是命令, 整体得到的是命令执行的结果(a= $(),a得到的是括号内命令执行的结果)

6. 变量使用实例

read的使用

将输入的值赋给后面的变量
例如

read -p "请输入用户名:" username


会把提示后的输入的值赋给变量 username
但如果不给提示加双引号,会出现下面情况

如果我们设置输入密码

read -s -p "请输入密码:" password

前面加上-s 在我们输入时就不显示输入的内容了 安全性高点

read 还有一个 -t方法 ,限定在多少秒内输入 ,否者就退出输入

read -t 3 -p "请输入用户名:" username

限定用户三秒内 输入

局部变量和全局变量

局部变量 : 新定义的变量默认只在当前的Shell环境中生效,无法在子Shell环境中使用
全局变量 :全局变量在当前Shell和子Shell环境中均有效
设置一个局部变量

a=11

在当前的Shell中有效,但在bash中无效

下面我们设置一个全局变量

export b=22

可以看出在当前Shell中有效,在bash中也有效

四. Shell中基本运算

1. 整数运算

Shell 中有 + - * / %(取余)
下面演示一下
主要的执行方式 有两种

  1. $(())
  2. $[]

    同时也支持一些简写表达式
简写表达式完整表达式
i++i=i+1
i- -i=i-1
i+=2i=i+2
i-=2i=i-2
i*=2i=i*2
i/=2i=i/2
i%=2i=i%2

2. 小数运算

Bash内建机制仅支持整数运算,不支持小数运算,我们可以通过计算机软件bc实现小数运算
bc支持交互式和非交换式两种方式计算,scale=n可以约束小数位
交互执行

非交互执行

bc也同样支持比较操作符
表达式成立返回1,不成立返回0

五. 条件测试

1. test测试操作

语法格式

  1. test 选项 参数
  2. [ 选项 参数 ]

基本语法:
是否为空[ -z 字符串 ]

等于 [ 字符串1 == 字符串2 ]

不等于[ 字符串1!= 字符串2 ]

显示 0 为正确

显示 非0 为不成立

2. 整数值比较

格式:[整数值1 操作符 整数值2]

操作符含义
-eq等于
-ne不等于
-ge大于或等于
-le小于或等于
-gt大于
-lt小于

应用

2 大于 1 ,输出 0符合
2 不大于 3, 输出 1(非0)不符合

3. 文件状态测试

操作符含义
-e判断对象是否存在,若存在则结果为真
-d判断对象是否为目录
-f判断对象是否为一般文件
-r判断对象是否有可读权限
-w判断对象是否有可写权限
-x判断对象是否有可执行权限

应用
/etc/ 为存在对象
/eeee/ 不纯在

4. 组合命令

我们可以使用控制符将多个命令组合
格式 : 命令1 控制符 命令2
控制符有:

  1. : 前后两个命令没有逻辑关系,先执行前面的命令,然后再执行后面的命令,无论前面的命令是否执行成功 ,都会执行后面的命令。
  2. && : 先执行前面的命令,然后再执行后面的命令,唯有前面的命令成功,才会执行后面的命令。
  3. || :先执行前面的命令,然后再执行后面的命令,当前面的命令执行成功时,便不在执行后面的命令,只有前面的命令执行不成功,才会执行后面的命令

应用
先进入 /root/shell 目录,再查看目录内容,会显示day1

打印 day1 表示 两条命令执行成功

我们也可利用 && 和 || 来实现多个条件的判断

[判断1] || [判断2]
[判断1] && [判断2]

5. 监控脚本基础知识

tr -s :删除多余重复的字符
例如 将 “a b c”中多余重复的空格去掉

echo "a    b    c" | tr -s " "


最终字母之间都只留下了一个空格

cut过滤
格式 : cut -d分割符号 -第几列 目标文件
类如 我们以 /etc/passwd 为目标文件,以 为分隔符号 ,获取第一列内容

cut -d: -f1 /etc/passwd


六. if语句

1. 单分支if语句

格式1:

if 条件
	then 命令
fi

格式2:

if 条件 ;then
	命令
fi

两种格式都可以使用 ,如果条件成立,执行命令,否者什么也不做。
下面来写一个创建用户脚本
条件为用户名和密码都不能为空,命令是创建用户并修改密码,最后的 echo 打印空 ,也就是换行。
由于 read pass 带了 -s 所以输入的密码不显示,实际是输入了密码。

read -p "请输入用户名:" user
read -s -p "请输入密码:" pass
if [ ! -z "$user" ]&&[ ! -z "$pass" ];then
         useradd "$user"
         echo "$pass" | passwd  --stdin "$user"
 fi
echo     


2. 双分支if语句

格式1:

if 条件
	then 命令1
else
	命令2
fi

格式2:

if 条件;then
	命令1
else
	命令2
fi

格式3:

if 条件1;then
	命令1
elif 条件2; then
	命令2
......
else
	命令n+1
fi

下面写一个例子:
测试主机是否能ping通

#!/bin/bash
  

if [ -z "$1" ];then
        echo -n "用法:脚本"
        echo -e "\\033[32m域名或IP\\033[0m"
        exit
fi
ping -c2 -i0.1 -W1 "$1" &>/dev/null
if [ $? -eq 0 ];then
        echo "$1 is up"
else
        echo "$1 is down"
fi
echo

-c2 :ping两次结束
-i0.1:ping的间隔是0.1秒
-W1 :ping的反应时间为1秒,若ping的反应时间超过1秒,默认ip ping不通

当我们什么都不输入时,会提示格式,当我们随便输入一个ip,显示ip 关闭 ,当我们输入自己的ip时显示 ip 开启

七. for 循环

根据变量的不同取值,重复执行命令序列
格式1:

for 变量 in 值列表
do
	命令
done

格式2:

for ((初值;条件;步长))
do
	命令
done

下面举个例子(格式1)

#!/bin/bash  

for i in 1 23 abc 2g
do
        echo "I am $i"
done


可以看出循环执行了5次,将in后内容遍历了一遍

格式1中的值列表有多种表示方式,也可以这样写

for i in 1..10
for i in a..z
for i in A..Z

表示1到10,a到z,A到Z

下面再举个例子(格式2)

#!/bin/bash
  
for((i=1;i<=5;i++))
do
        echo "I am $i"
done

这个就不必多说了。

99乘法表

下面来运用for循环的格式2来写一个99乘法表

#!/bin/bash
  
for((i=i;i<=9;i++))
do      
        for((j=1;j<=i;j++))
        do      
                echo -n "$i*$j=$[i*j]"
        done    
        echo
done  

八. while循环

条件式循环,反复测试条件,只要成立就执行命令序列。
格式:

while 条件
do 
	命令
done

举个例子
遍历输出1-5

#!bin/bash

i=1
while [$i -le 5 ]
do
        echo $i
        let i++
done  

猜数字游戏

给出一个10以内的随机数让玩家猜,如果输入的数大于随机数,会显示猜大了,如果输入的数小于随机数,则显示猜小了。

#!/bin/bash
  

num=$[RANDOM%10+1]
while:
do      
        read -p "请输入1-10之间的整数:" guess
        if [$guess -eq $num ];then
                echo "恭喜你,猜对了"
                exit
        elif [ $guess -lt $num ];then
                echo "猜小了"
        else    
                echo "猜大了"
        fi      
done 

九. case语句

效果类似于多分支的if语句,如果与预设的值相匹配,则执行相应的操作,命令最后以 ; 结尾,如果都不匹配,则执行默认命令。
格式:

case 变量 in 
模式1)
	命令1;;
模式2)
	命令2;;
......
*)
	默认命令
esac

举一个例子
输入 tom 输出 I am tom ,输入tome 输出 I am tome ,输入其他的 则 输出 暂无此人。

#!/bin/bash
  
read -p "请输入tom 或者 tome:" key
case $key in
tom)
        echo "I am tom";;
tome)
        echo "I am tome";;
*)
        echo "暂无此人"
esac

石头剪刀布游戏

运用数组和case语句来创造一个石头剪刀布游戏脚本,系统会随机选择出拳的方式。

#!/bin/bash
  
gane=(石头 剪刀 布)
num=$[RANDOM%3]
computer=$game[$num]
#通过随机数获取系统的出拳
#出拳的可能保存在一个数组中:game[0],game[1],game[2]

echo "请根据下列提示选择您的出拳方式"
echo "1.石头"
echo "2.剪刀"
echo "3.布"

read -p "请选择1-3:" person
case $person in
1)      
        if [ $num -eq 0];then
                echo "平局"
        elif [ $num -eq 1 ];then
                echo "你赢"
        else    
                echo "电脑赢"
        fi;;
2)      
        if [ $num -eq 0 ];then
                echo "电脑赢"
        elif [ $num -eq 1 ];then
                echo "平局"
        else    
                echo "你赢"
        fi;;
3)
        if [ $num -eq 0 ];then
                echo "你赢"
        elif [ $num -eq 1 ];then
                echo "电脑赢"
        else
                echo "平局"
        fi;;    
*)
        echo "必须输入1-3的数字"
esac 

数组

数组是一个特殊的变量,它是能够储存多个数据的集合
格式:

数组名=(数值1 数值2 数值3 ...)

下面来演示一下
创建一个名为 test 的数组

十. shell函数

在Shell环境中,将一些需要重复使用的操作,定义为公共的语句块,既可称为函数
格式1:

function 函数名
	命令
	...

格式2:

函数名()
	命令
	...

范例
不带参数的函数

imsg()
	echo "hello world"
	echo "compute cloud"
	


带参数的函数

add()
echo $[$1+$2]


带颜色的函数
\\033[:开启设置字体颜色
\\033[0m : 关闭设置字体颜色

#!/bin/bash
  
cecho()
        echo -e " \\033[$1m$2\\033[0m"

cecho 31 OK  #参数是字体的颜色
cecho 32 OK
cecho 33 OK
cecho 34 OK

十一. 中断和退出

脚本中的中断和退出命令
continue : 可以结束单次循环
break :可以结束循环体
exit :可以退出脚本
下面举几个例子
首先是continue ,当遍历到 3 时,跳过本次循环

然后是 break
当遍历到 3 时跳出循环

最后是 exit
如果是在脚本文件中,会退出脚本,如果在xshell中直接exit,则会退出连接。

十二. 字符串的处理和变量的初始化

统计变量长度

test=123456789
echo $#test

1. 字符串的截取

格式:$变量:起始位置:长度

text=123456789

从第0位开始往后截取3位

echo $test:0:3


从第3位开始,往后截取3位

echo $test:3:3


从第四位开始,截取到最后一位

echo $test:4


从第四位开始,截取到倒数第二位

echo $test:4:-2

2. 字符串的替换

替换一个结果
格式:$变量/旧字符/新字符
替换全部结果
格式:$变量//旧字符/新字符

示例

3. 字符串的掐头去尾

掐头

字符串的掐头都是从左到右,且不会改变变量原来的值
最短匹配
格式 : $变量#关键词
最长匹配
格式:$变量##关键词
举例
定义变量 test=123:456:789
分别最短匹配掐头和最长匹配掐头
*:表示 前面的所有部分

去尾

去尾的顺序是从右往左,同样不会改变变量原来的值
最短匹配
格式: $变量%关键词
最长匹配
格式:$变量%%关键词

举例
与上面的例子差不多
因为顺序改变了,所以 * 的位置也变了一下

4. 变量初始化

判断一个变量是否有值,如果有值返回该变量的值,如果没有值,则返回初始值
格式:$变量:-初始值

示例
此处给a变量赋值,b没有赋值,使用变量格式化,a返回原有的值,b返回变量初始化的值。

5. 随机密码

定义变量:10个数字+52个字母,用随机数对62取余数,返回的结果为[0-61],然后将其作为key的字符串位数取出字符,随机取10次,得到一个10位的随机密码。

#!/bin/bash
  
key="1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
pass=""

for i in 1..10
do
        num=$[RANDOM%$#key]
        tmp=$key:num:1
        pass=$pass$tmp
done
echo $pass
       

使用命令生成随机密码

  1. uuidgen:生成随机序列号
  2. openssl: 生成可控长度的随机序列号,例子后面的15不是指的序列号的长度,而是一个控制值,值越大,序列号越长。

使用随机设备文件生成随机密码

/dev/random : 能够一直产生随机码,不会自动终止,效率很慢,大概十几秒出一次。

/dev/urandom: 这个文件也能源源不断的产生随机码,而且效率很高。

十三. 正则表达式

描述一个字符集合的表达方式,根据特征模糊的匹配内容。

1. 基本正则符号

正则符号描述
abc匹配abc
^匹配开头
$匹配结尾
[集合]匹配集合中的任意单个字符
[ ^ 集合]对集合取反
.匹配任意单个字符
*匹配前一个字符任意次(包含0次)
.*匹配任意
n,m匹配前一个字符n到m次
n,匹配前一个字符至少n次
n匹配前一个字符n次

2. 扩展正则符号

正则符号描述
+匹配前面的字符至少一次
匹配前面的字符0或一次
()组合与保留
|或者
n,m匹配前面的字符n到m次
n,匹配前面的字符至少n次
n匹配前面的字符n次

3. Perl兼容的正则符号

正则符号描述
\\b匹配单词边界
\\w匹配字符数字下划线
\\W和\\w相反
\\s匹配空白
\\d匹配数字
\\d+匹配多个数字
\\D匹配非数字

4. grep语法

grep语法支持正则表达式,下面介绍一下grep语法,以及一些正则表达式的练习示例。
格式: grep [选项] 匹配模式 [文件]...
常用的选项:
-i:忽略大小写
-v:取反匹配(全部)
-w:匹配单词
-q:静默匹配,不将结果显示在屏幕上

下面来介绍一些练习的指令
创建一个名为 test.txt 的文件,并在里面写上足够的内容

  1. 过滤文件中 带 the 的行
grep the test.txt

  1. 过滤文件中带 the 的行,不区分大小写
grep -i the test.txt

  1. 过滤包含数字的行
grep "[0-9]" test.txt
grep -P "\\d" test.txt

  1. 过滤包含 in和the 的行
  2. <

    以上是关于Shell脚本保姆级教程的主要内容,如果未能解决你的问题,请参考以下文章

    保姆级教程: c++游戏服务器嵌入v8 js引擎

    Hadoop 3.1.3 分布式集群搭建,超详细,保姆级教程

    通过 docker-compose 快速部署 Redis 保姆级教程

    保姆级教程:写出自己的移动应用和小程序(篇六)

    教你使用最新版的ChatGPT(保姆级教程)

    游戏开发教程BehaviorDesigner插件制作AI行为树(Unity | 保姆级教程 | 动态图演示 | Unity2021最新版)