文章

Shell基础


Shell含义

Linux内核用于驱动硬件;而用户使用应用程序想要与硬件交互则需要Shell程序

Shell 是一个程序,提供一个与用户对话的环境。这个环境只有一个命令提示符,让用户从键盘输入命令,所以又称为命令行环境(command line interface,简写为 CLI;图形界面(GUI))。Shell 接收到用户输入的命令,将命令送入操作系统执行,并将结果返回给用户。

👣bash是Shell的一种..

bash大多数 Linux 系统默认使用的 shell.


Shell种类

  • Bourne Shell
  • Bourne Again shell(bash)
  • C Shell(csh)
  • TENEX C Shell(tcsh)
  • Korn shell(ksh)
  • Z Shell(zsh)
  • Friendly Interactive Shell(fish)

事先注意事项

  • 函数定义必须在执行语句之前,也就是#!bin/bash下面,否则后面执行函数调用将无法被调用,会提示command not found
  • 创建变量名称时不能以数字开头
  • 创建变量赋值;等号两侧不能有空格
  • 变量默认类型都是字符串类型,无法直接进行数值运算
  • 变量值有空格,需要使用双引号或单引号括起来

Debug模式

1
2
3
4
5
6
7
#全局开启Debug
set -x      #开启Debug模式;输入每个命令都会显示执行过程;切勿在命令行开启
set +x      #关闭Debug模式
#只针对脚本开启Debug
bash -x     #只显示脚本的执行过程
#带+号表示执行过程
#没带加号表示标准输出

命令提示符

进入命令行环境以后,用户会看到 Shell 的提示符。提示符往往是一串前缀,最后以一个美元符号$结尾,用户可以在这个符号后面输入各种命令

1
[user@hostname] $

上面例子中,完整的提示符是[user@hostname] $,其中前缀是用户名(user)加上@,再加主机名(hostname)。比如,用户名是bill,主机名是home-machine,前缀就是bill@home-machine

注意,根用户(root)的提示符,不以美元符号($)结尾,而以井号(#)结尾,用来提醒用户,现在具有根权限,可以执行各种操作,务必小心,不要出现误操作。

查看当前设备默认的Shell

1
root@R-PC:/# echo $SHELL

查看当前Linux系统安装的所有Shell

1
root@R-PC:/# cat /etc/shells

Shell脚本格式


基本格式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/bin/bash   #定义一个解释器
变量名 = "$(Shell命令)"
echo $变量名                    #使用一个定义过的变量,只要在变量名前面加美元符号即可  
echo "$(touch 文件名(PAth))"     #创建文件
echo $变量名 >> 文件名           #将输出的指令内容写入到这个文件

#函数用法
函数名(){
         语句
}
函数名         #调用函数

#read用法(接收用户输入)
read  [自定义变量名]
echo $[自定义变量名]
#将用户的输入自动保存到这个变量中,可以用echo $变量名输出显示

局部变量


撤销变量-unset-

1
2
3
4
5
root@wyw-PC:~# a=1
root@wyw-PC:~# echo $a
1
root@wyw-PC:~# unset a
root@wyw-PC:~# echo $a

声明静态变量-readonly-

注意:不能撤销(unset)

1
2
3
4
5
root@wyw-PC:~# readonly a=1
root@wyw-PC:~# echo $a
1
root@wyw-PC:~# unset a
bash: unset: a:无法取消设定: 只读 variable

全局变量


将局部变量提升为全局变量-export-

1
2
root@wyw-PC:/bin# export A=2
#意味着到哪个路径或哪个.sh文件里面都可以使用这个变量

特殊变量


$n

功能描述:

  • 传递给脚本或函数的参数

  • n为数字,$0获取当前脚本文件名称

  • $1~$9代表输入的第1到第9个参数

  • 10以上的参数需要用大括号包含,如${10}

$#

功能描述:

  • 获取所有输入参数的个数(判断你输入的有几个参数,用于循环)

$*

功能描述:

  • 所有输入的参数

  • $*把所有参数看成一个整体(整体输出)

$@

功能描述:

  • 所有输入的参数

  • $@把每个参数区别对待(逐个输出)

$?

功能描述:

在Linux系统中,每当一条命令执行完成后,系统都会返回一个退出状态,这个状态被存放在$? 这个变量中,是一个整数值,我们可以根据这个值来判断命令运行的结果是否正确。

通常情况下,退出状态值为0,表示执行成功,不为0的时候表示执行失败。

1
2
3
4
5
6
7
8
9
0 (运行成功)

1-255 (运行失败,脚本命令、系统命令错误或参数传递错误)

126 (找到了该命令但无法执行)

127 (未找到要运行的命令)

128 (命令被系统强行结束)

Read用法(用户提示输入)

1
2
3
#!/bin/bash
read -t 3 -p "3秒内输入参数赋值给变量" A    #将用户的输入赋值给变量A
echo $A

参数

  • -t 用户输入的等待时间
  • -p 脚本执行时对用户输入的提示信息

提示

  1. 不跟时间参数会一直等待用户输入
  2. 用户输入的值最后会赋值给创建的变量

运算符


加减乘除取余运算(+ , - , \ * , / , %)-expr-、乘号(\ *)

注意:expr运算符之间要有空格

1
2
root@wyw-PC:/# expr `expr 2 + 2` \* 2     # ` `表示优先执行
8

采用$[运算式]方式、乘号(*)

1
2
3
root@wyw-PC:/# A=$[(2+3)*4]      #这里的乘号与expr方式有所区别
root@wyw-PC:/# echo $A
20

[ 条件 ]

  • [ ]用于存放判断条件
  • 条件前后要有空格

  • 利用echo $?输出结果;结果为0即为真,为0及为假
1
2
3
4
5
6
root@wyw-PC:/# [ 23 -lt 22 ]
root@wyw-PC:/# echo $?
1
root@wyw-PC:/# [ 23 -gt 22 ]
root@wyw-PC:/# echo $?
0

test 条件

1
2
3
4
5
# -v 变量名,用于判断变量是否定义;结果为0即定义
# -e 文件名,用于判断文件是否存在
[root@VM-0-5-centos ~]# test -e if.sh
[root@VM-0-5-centos ~]# echo $?
0

整数比较运算符

两个整数之间比较

1
2
3
4
5
6
7
=  字符串比较

-eq 等于(equal)               -ne 不等于(Not equal)

-lt 小于(less than)           -le 小于等于(less equal)

-gt 大于(greater than)        -ge 大于等于(greater equal)

字符串相关运算符

1
2
3
4
-n string            # 字符串不为空则为真
-z string            # 字符串为空则为真
string1 = string2    # 字符串相等则为真 (或者 == 也可以)
string1 != string2   # 字符串不等则为真

这里有一个需要注意的地方,就是使用 -n 这个运算符进行判断的时候需要注意在变量两边加上双引号。

例如 if [ -n $string ] 应该写成 if [ -n “$string” ] ,不然该表达式总是会返回真,因为当string变量为空的时候就相当于是 if [ -n ]。

文件权限操作符

1
2
3
4
5
-r   读权限(read)

-w  写权限(write)

-x   执行权限(execute)
1
2
3
root@wyw-PC:/# [ -x xunjian.sh ]
root@wyw-PC:/# echo $?
1

文件类型操作符

1
2
3
4
5
6
7
8
9
-d file # 测试file是否为目录
-e file # 测试file是否存在
-f file # 测试file是否为普通文件
-r file # 测试file是否是进程可读文件
-s file # 测试file的长度是否不为0
-w file # 测试file是否是进程可写文件
-x file # 测试file是否是进程可执行文件
-l file # 测试file是否符号化链接
-c file #判断是不是一个字符设备文件
1
2
3
root@wyw-PC:/# [ -d 123 ]       #123为文件名称
root@wyw-PC:/# echo $? 
0

|逻辑运算符

1
2
3
!     # 非
-a  # 与(或者&&)
-o  # 或(或者||)
1
2
3
4
5
6
7
8
9
if [ $value == "stop" -o $value == "restart" ]; then
  excute=$value
fi  

或者

if [ $value == "stop" ] || [ $value == "restart" ]; then
  excute=$value
fi  

if判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/bin/bash
if  [ 条件 ];then  或者  if [ 条件 ]   换行then

程序

elif [ 条件 ];then

程序

fi      #结束

#第三种嵌套写法
if [];then
  程序
else
   if [];then
     程序
   else
     程序
   fi
fi

case语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/bash
case $变量名 in  
变量值1)
   程序输出...
;;               #匹配上双分号结束
变量值1)
   程序输出...
;;               #匹配上双分号结束

..........

*#相当于默认值default;其他都不匹配就匹配默认值
   程序输出...
;;               #匹配上双分号结束
esac             #结束

for循环

写法一

1
2
3
4
5
#!/bin/bash
for ((①初始值;②循环控制条件;④变量变化))   #执行流程①②③④
do
   ③程序
done                 #do和done对应大括号{}

写法二(类似与Python中的遍历循环)

1
2
3
4
5
#!/bin/bash
for 变量名 in 变量值1 变量值2 变量值3    #将变量值依次赋值给变量,类似与Python中的遍历
do  
    程序
done

while循环

1
2
3
4
5
while [ ①条件判断 ]
do
    程序②
    程序③
done

函数


系统函数’

basename删除前面文件路径,截取文件名称

格式

1
2
3
4
5
6
7
basename   [文件路径/前缀字符]  [要被截取的后缀]
[root@VM-4-7-centos /]# basename 123.sh .sh   #截取文件名称
123
[root@VM-4-7-centos /]# basename bin in
b
[root@VM-4-7-centos /]# basename 123 23     #截取字符
1
dirname删除后面文件名称,截取文件路径

格式

1
2
[root@VM-4-7-centos /]# dirname data/v2ray.crt
data

自定义函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#必须先声明函数,不然无法调用
function(可写可不写) 函数名称()
{
      程序内容
}
函数名称调用()

#示例
#!/bin/bash
function sum()
{
   s=0
   s=$[$1+$2]
   echo $s
}
read -p "输入域名:" DNS
read -p "输入IP地址:" IP

sum $DNS $IP

Shell工具


截取列工具- cut -

作用:在一大堆数据当中剪出核心关键的

选项参数

-f 取出第几列或者第几列到第几列(1-7…….)

-d 指定分隔符(分割列);以什么符号分割列

-c 从第几个字符开始取值;可以是以逗号分隔的数字的列表,也可以是以连字符分隔的数字的范围

-b 提取指定的字节,也可以指定一个范围

文本过滤工具- grep -

文本编辑工具- sed -

替换、添加、删除

格式

sed 参数 ‘ 执行动作 ‘ 文件名

^表示首行或者是^root以root开头的那一行 $表示尾行

[参数]:

  • -i 对源文件进行修改
  • -e 不会修改源文件
  • -n 显示行数

'’动作’‘:

  • a 添加;当前的下一行
  • i 插入;当前的上一行
  • d 删除
  • s 替换
  • p 打印第几行;结合-n使用;例如 sed -n “4p” 就是输出打印第四行内容

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
#  N表示第几行
#  'N,Ns/d/a...'   指定范围
 
#添加a
sed 'Na 文本内容'  文件名       #在指定当前行数的下一行添加内容

#删除d
sed  '/要被删除的文本/d'  文件名   #删除匹配上文本的行
sed  'Nd'   文件名        #删除某一行
#替换s
sed 's/要被取代的文本/新的文本/g'  文件名     #匹配文件中所有要被替换的文本;加g是全局替换,不加默认匹配替换第一个
sed 'Ns/要被取代的文本/新的文本 /'  文件名  #指定某一行匹配要被替换的文本
sed 'N,Ns'              #替换指定行数范围之间所匹配的文本

统计、分析日志、过滤 - awk -

擅长数据切片,数据格式化,功能最复杂

正则表达式

^ 如:”awk^”,匹配以awk单词开头的行
$ 如:”awk$”,匹配以awk单词结尾的行
^$ 表示空行(头尾什么都没有)
. 匹配任意一个字符且只有一个字符,不能匹配空行
\ 转义字符,使\后面的字符按愿意输出,还原本意,如:”\ .” 代表小数点
*  
.* 匹配所有内容
^.* 匹配以任意多个字符开头的内容
.*$ 匹配以任意多个字符结尾的内容
[a b c] 匹配集合内任意一个字符,a或者b或者c,也可以写成[a-c]
^[a b c] 匹配以集合内任意一个字符开头的内容
[^a b c] 匹配不以集合内任意一个字符开头的内容

输出彩色字体


至少需要两部分, \033[31m 和\033[0m

\033[31m理解成”开始输出红色字符” ,把\033[0m理解成”结束输出红色字符”

1
2
3
4
#输出红色字体
echo -e  "\033[1;32m文本\033[0m"
#分号前代表背景色
#分号后代表字体颜色

定义变量值为一个命令

1
2
3
root@wyw-PC:/# B="$(ls)"            #调用定义过的变量,要变量名前面加$符号即可
root@wyw-PC:/# echo $B
123.sh bin boot data dev etc home lib lib32 lib64 libx32 lost+found media proc recovery root run sbin server.sh srv sys tmp usr var wyw xunjian.sh
1
2
3
A=1    #给变量赋值(初始化)
A      #变量
$A     #调用变量(变量值)

Shell脚本保存格式:文件名.sh

执行格式:./文件名.sh(一般没有执行权限) 或者 shell种类(bash、sh等) 文件名.sh

本文由作者按照 CC BY 4.0 进行授权