shell学习笔记

Shell脚本学习笔记

一、文本处理工具

1.1 grep工具:

​ grep是行过滤工具;用于根据关键字进行过滤

​ 语法和选项:

# grep 选项 '关键字' 文件名

​ 常见选项:

OPTIONS:
     -i:不区分大小写
     -v:查找不包含指定内容的行,反向选择
     -w:按单词搜索
     -o:打印匹配关键字
     -c:统计匹配到的次数
     -n:显示行号
     -r:逐层遍历目录查找
     -A:显示匹配行及后面多少行
     -B:显示匹配行及前面多少行
     -C:显示匹配行前后多少行
     -l:只列出匹配的文件名
     -L:列出不匹配的文件名
     -e:使用正则匹配
     -E:使用扩展正则匹配
     ^key:以关键字开头
     key$:以关键字结尾
     ^$:匹配空行
     --color=auto:可以将找到的关键词部分加上颜色的显示
     

1.2 cut工具

​ cut是列截取工具,用于列的截取

语法:

# cut 选项   文件名

常见选项:

-c:以字符串为单位进行分割,截取
-d:自定义分隔符,默认为制表符\t
-f:与-d一起使用,指dd定截取哪个区域

举例说明:

# cut -d: -f1 1.txt           以:冒号分隔,截取第1列内容
# cut -d: -f1,6,7  1.txt      以:冒号分隔,截取第1,6,7列内容
# cut -c4  1.txt              截取文件中每行第4个字符
# cut -c1-4  1.txt            截取文件中每行的1-4个字符
# cut -c4-10  1.txt           截取文件中每行的4-10个字符
# cut -c5-  1.txt             从第5个字符开始截取后面所有字符

课堂练习:

1、用小工具列出你当前系统的运行级别

2、如何过滤运行级别?

1.3 sort工具

​ sort工具用于排序;它将文件的每一行作为一个单位,从首字符向后,依次按ASCII码值进行比较,最后将他们按升序输出。

语法和选项

-u : 去除重复行
-r : 降序排列,默认是升序
-o : 将排序结果输出到文件中,类似重定向符号>
-n : 以数字排序,默认是按字符排序
-t : 分隔符
-k : 第N列
-b : 忽略前导空格
-R : 随机排序,每次运行的结果均不同

举例说明

# sort -n -t:  -k3  1.txt                           按照用户的uid进行升序排列
# sort -nr -t: -k3  1.txt                           按照用户的uid进行降序排列
# sort -n  2.txt                                    按照数字排序
# sort -nu  2.txt                                   按照数字排序并且去重
# sort -nr  2.txt
# sort -nru  2.txt
# sort -nru  2.txt
# sort -n 2.txt  -o 3.txt                           按照数字排序并将结果重定向到文件
# sort -R 2.txt  
# sort -u 2.txt

1.4 uniq工具

​ uniq用于去除连续的重复行

常见选项:

-i :忽略大小写
-c :统计重复行次数
-d :只显示重复行

举例说明:

# uniq 2.txt
# uniq -d 2.txt
# uniq -dc 2.txt

1.5 tee工具

tee工具是从标准输入读取并写入到标准输出和文件,即:双向覆盖重定向(屏幕输出|文本输入)

常见选项:

-a 双向追加重定向
# echo hello world
# echo hello world|tee file1
# cat file1
# echo 999|tee -a file1
# cat file1

1.6 diff工具

​ diff工具用于逐行比较文件的不同

​ 注意:diff描述两个文件不同的方式是告诉我们怎样改变第一个文件之后与第二个文件匹配。

语法和选项:

-b: 不检查空格
-B: 不检查空白行
-i: 不检查大小写
-w: 忽略所有空格
--normal: 正常格式显示(默认)
-c: 上下文格式显示
-u: 合并格式显示

举例说明:

#比较两个普通文件异同,文件准备
[root@AliYun home]# cat file1 
hello
world
this is test
[root@AliYun home]#

[root@AliYun home]# cat file2
aaa
hello
222
bbb
333
[root@AliYun home]# 

其他小技巧

1、找出文件不通,然后输出到一个文件
[root@AliYun home]# diff -uN file1 file2 >file.patch
-u:上下文模式
-N:将不存在的文件当作空文件

2、将不通内容打补丁到文件
[root@AliYun home]# patch file1 file.patch 
patching file file1

3、测试验证
[root@AliYun home]# diff file1 file2
[root@AliYun home]# 

1.7 paste工具

paste工具用于合并文件行

常用选项:
-d:自定义间隔符,默认是tab
-s:串行处理,非并行

例如:
1、先清空下两个文件中的内容
[root@AliYun shell]# > file1
[root@AliYun shell]# > file2

[root@AliYun shell]# cat -n file1
     1	hello world
     2	hahaha
[root@AliYun shell]# cat -n file2
     1	heima ittest
     2	666
     3	myself best
[root@AliYun shell]# 
[root@AliYun shell]# paste file1 file2       #使用默认参数,不加任何选择
hello world	heima ittest                     #fiel1的hello world与fiel2的heima ittest合并了
hahaha	666                                  #fiel1的hahaha与fiel2的666合并了
myself best                                  #file1的第三行无内容,所以合并后只显示了file2的第三行内容 
[root@AliYun shell]#
[root@AliYun shell]# paste -d: file1 file2   #使用:进行分隔
hello world:heima ittest
hahaha:666
:myself best
[root@AliYun shell]#

1.8 tr工具

tr用于字符转换,替换和删除;主要用于删除文件中控制字符或进行字符转换

语法和选项
用法1: 命令的执行结果交给tr处理,其中string1用于查询,string2用于转换处理
# commands |tr  'string1'   'string2'
用法2: tr处理的内容来自文件,记住要使用"<"标准输入
# tr 'string1'  'string2'  < filename

常用选项:

-d 删除字符串1中所有输入字符。
-s 删除所有重复出现字符序列,只保留第一个;即将重复出现字符串压缩为一个字符串

常匹配字符串:

字符串含义备注
a-z或[:lower:]匹配所有小写字母[]
A-Z或[:upper:]匹配所有大写字母
0-9或[:digit:]匹配所有数字
[:alnum:]匹配所有字母和数字
[:alpha:]匹配所有字母
[:blank:]所有水平空白
[:punct:]匹配所有标点符号
[:space:]所有水平或者垂直的空格
[:cntrl:]所有控制字符\f Ctrl-L 走行换页
\n Ctrl-J 换行
\r Ctrl-M 回车
\t Ctrl-I tab键

实验:

1、使用小工具分别截取当前主机ip;截取netmask;截取广播地址;截取MAC地址

[root@AliYun shell]# ifconfig eth0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.24.9.222  netmask 255.255.192.0  broadcast 172.24.63.255
        inet6 fe80::216:3eff:fe32:a635  prefixlen 64  scopeid 0x20<link>
        ether 00:16:3e:32:a6:35  txqueuelen 1000  (Ethernet)
        RX packets 114118807  bytes 15992833986 (14.8 GiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 251027463  bytes 27313551216 (25.4 GiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

提取ip地址思路:先找关键词,然后使用tr删除所有字母,使用tr将所有空格替换成换行符,使用grep -v取反排除空行(^$)

[root@AliYun shell]# ifconfig eth0 |grep 'netmask'|tr -d 'a-zA-Z:'|tr ' ' '\n'|grep -v '^$'
172.24.9.222
255.255.192.0
172.24.63.255

提取mac地址思路:先找关键词,替换多个空格为1个空格,截取以空格分隔的第3列

[root@AliYun shell]# ifconfig eth0 |grep 'ether'|tr -s ' '|cut -d' ' -f3
00:16:3e:32:a6:35

2、将系统中所有普通用户的用户名、密码和默认shell保存到一个文件中,要求用户名密码和默认shell之间用tab键分割

提取思路:先从passwd中过滤出bash结尾的行,然后grep -v取反(不包含)root的行,然后列截取1,2,7行,然后使用tr将冒号替换成制表符(\t),然后使用tee工具读取并写入abc.txt文件中

[root@AliYun shell]# grep 'bash$' passwd |grep -v 'root'|cut -d: -f1,2,7|tr ':' '\t'|tee abc.txt
admin	x	/bin/bash
uyun	x	/bin/bash
chen	x	/bin/bash

1.9 sed工具

二、bash的特性

2.1 命令和文件的自动补全

​ Tab只能补全命令和文件

2.2 常见的快捷键

^c               终止前台运行的程序
^z               将前台运行的程序挂起到后台
^d               退出 等价exit  
^l               清屏 
^a |home         光标移动到命令行的最前端
^e |end          光标移动到命令行的后端
^u               删除光标前所有字符   
^k               删除光标后所有字符
^r               搜索历史命令 

2.3 常用的通配符

*:        匹配0或多个任意字符
?:        匹配任意单个字符
[list]:   匹配[list]中的任意单个字符
[!list]:  匹配除list中的任意单个字符
{string1,string2,...}:  匹配string1,string2或更多字符串

2.4 bash中的引号

  • 双引号“”: 会把引号的内容当成整体来看待,允许通过$符号引用其他变量值

  • 单引号‘’ : 会把引号的内容当成整体来看到,禁止引用其他变量值,shell中特殊符号都被视为普通字符

  • 反撇号``: 反撇号和$()一样,引号或括号里的命令会优先执行,如果存在嵌套,反撇号不能用

[root@AliYun ~]# echo "$(hostname)"
AliYun
[root@AliYun ~]# echo '$(hostname)'
$(hostname)
[root@AliYun ~]# echo "hello world"
hello world
[root@AliYun ~]# echo 'hello world'
hello world
[root@AliYun ~]# echo "$(date +%F)"
2021-04-28

三、Shell介绍

  • 熟练掌握Shell的基本语法结构

  • 熟练掌握shell变量的定义和获取

  • 了解基本正则表达式的运用

  • 熟练掌握文件处理三剑客:grep、sed、awk工具的使用

  • 使用shell脚本完成一些较为复杂的任务,如:服务搭建、批量处理等

  • 深入学习

3.1 shell简介

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hESrECIv-1642347486006)(C:\Users\chen\AppData\Roaming\Typora\typora-user-images\image-20210428234136807.png)]

总结

  • shell就是人机交互的一个桥梁

  • 常见的shell种类

[root@AliYun ~]# cat /etc/shells
/bin/sh                #是bash的第一个快捷方式
/bin/bash              #bash是大多数Linux默认的shell,包含的功能几乎可以涵盖shell所有功能
/sbin/nologin          #表示非交互,不能登录操作系统
[root@AliYun ~]# 

3.2 什么是shell脚本

  • 简单来说就是将需要执行的命令保存到文本中,按照顺序执行。它是解释型的,意味着不需要编译。

  • 准确描述:shell脚本=若干命令+脚本的基本格式+脚本特定语法+思想

3.3 脚本使用场景

重复化、复杂化的工作,通过把工作的命令写成脚本,以后仅需执行脚本就能完成这些工作。

3.4 shell脚本可以做什么?

  • 自动化软件部署 LAMP/LNMP/Tomacat

  • 自动化管理 系统初始化脚本、批量更改主机密码、随送公钥

  • 自动化分析处理 统计网站访问量

  • 自动化备份 数据库备份、日志转储…

  • 自动化监控脚本

3.5 如何学习shell

  • 尽可能记忆更多的命令
  • 掌握脚本的标准格式
  • 熟练掌握脚本的基本语法
  • 多看、多练

3.6 Shell脚本的基本写法

1)脚本第一行,魔法字符#!指定解释器【必写】

!#/bin/bash                   表示以下内容使用bash解释器解析

注意:

如果直接将解释器路径写死在脚本里,可能在某些系统就会存在找不到解释器的兼容性问题,所以可以使用:#!/bin/env解释器

2)脚本第二部分,注释(#号)说明,对脚本的基本信息进行描述【可选】

#!/bin/env bash

#以下内容是对脚本基本信息的描述
#Name:名字
#Desc:描述describe
#Path:存放路径
#Usage: 用法
#Update: 更新时间

#下面就是脚本的具体内容
commands
...

3)脚本第三部分,脚本要实现的具体代码内容

3.7 Shell脚本的执行方法

1. 标准脚本执行方法:

#!/bin/env bash          标准脚本开头,加env参数则该脚本可以在任意环境执行
[root@AliYun app]# ll
total 8
-rwxrwxr-x 1 uyun uyun 696 Apr 15 20:48 network_backup.sh
-rw-r--r-- 1 root root  34 Apr 29 23:02 one_shell.sh
drwxr-xr-x 2 uyun uyun   6 Apr 25 10:17 uyun
[root@AliYun app]# chmod +x one_shell.sh 
[root@AliYun app]# ll
total 8
-rwxrwxr-x 1 uyun uyun 696 Apr 15 20:48 network_backup.sh
-rwxr-xr-x 1 root root  34 Apr 29 23:02 one_shell.sh
drwxr-xr-x 2 uyun uyun   6 Apr 25 10:17 uyun
[root@AliYun app]# pwd
/app
[root@AliYun app]# ll
total 8
-rwxrwxr-x 1 uyun uyun 696 Apr 15 20:48 network_backup.sh
-rwxr-xr-x 1 root root  35 Apr 29 23:04 one_shell.sh
drwxr-xr-x 2 uyun uyun   6 Apr 25 10:17 uyun
[root@AliYun app]# sh one_shell.sh 
20210429

注意:标准执行方式脚本必须要有可执行权限

2. 非标准脚本执行方法:

  1. 直接在命令行指定解释器执行
-x: 一般用于排错,查看脚本的执行过程
-n: 用来查看脚本的语法是否有问题
  1. 使用source命令读取脚本文件,执行文件里的代码

3. 实验:写一个简单脚本,要求如下:

  • 删除/tmp/目录下的所有文件

  • 然后在/tmp/目录中创建10个目录,分别是dir1-dir10

  • 拷贝/etc/hosts文件到刚创建的dir1目录里

  • 最后打印“恭喜你,你的第一个脚本已于2021-04-29 23:20时间完成”内容

[root@AliYun tmp]# ll
total 16
drwxr-xr-x 2 root root   6 Apr 29 23:52 agent
-rw-r--r-- 1 root root  13 Apr 29 23:50 file1
-rw-r--r-- 1 root root  14 Apr 29 23:50 file2
-rw-r--r-- 1 root root  18 Apr 29 23:53 network
-rwxr-xr-x 1 root root 696 Apr 29 23:51 network_backup.sh
drwxr-xr-x 2 root root  45 Apr 29 23:49 student
drwxr-xr-x 3 uyun uyun  21 Apr 29 23:51 uyun

#!/bin/bash
rm -rf /tmp/*
mkdir -p /tmp/dir{1..10}
cp /etc/hosts /tmp/dir1
echo "你创建了以下目录"
ls -l /tmp/
echo "恭喜你,你的第一个脚本已于2021年4月29日完成!"
[root@AliYun app]# cd /tmp
[root@AliYun tmp]# ll
total 0
drwxr-xr-x 2 root root 6 Apr 29 23:59 dir1
drwxr-xr-x 2 root root 6 Apr 29 23:59 dir10
drwxr-xr-x 2 root root 6 Apr 29 23:59 dir2
drwxr-xr-x 2 root root 6 Apr 29 23:59 dir3
drwxr-xr-x 2 root root 6 Apr 29 23:59 dir4
drwxr-xr-x 2 root root 6 Apr 29 23:59 dir5
drwxr-xr-x 2 root root 6 Apr 29 23:59 dir6
drwxr-xr-x 2 root root 6 Apr 29 23:59 dir7
drwxr-xr-x 2 root root 6 Apr 29 23:59 dir8
drwxr-xr-x 2 root root 6 Apr 29 23:59 dir9

四、变量的定义

4.1 变量是什么?

一句话概括:变量是用来临时保存数据的,该数据是可以变化的数据。

4.2 什么时候需要定义变量?

  • 如果某个内容需要多次使用,并且在代码中重复出现,那么可以用变量代表该内容。这样在修改内容的时候,仅仅需要修改变量的值

  • 在代码运作的过程中,可能会把某些命令的执行结果保存起来,后续代码需要使用这些结果,就可以直接使用这本变量。

3、变量如何定义?

变量名=变量值

变量名:用来临时保存数据的

变量值:就是临时的数据

[root@AliYun ~]# A=hello        #定义变量A
[root@AliYun ~]# echo $A        #调用变量A,调用变量需要在变量名前使用$符号  
hello 
[root@AliYun ~]# echo ${A}      #还可以在变量名前使用${}
hello
[root@AliYun ~]# A=world        #重新给变量赋值
[root@AliYun ~]# echo $A        #因为上面已经给变量A重新赋值,所以此时调用变量A返回的值发生了变化
world
[root@AliYun ~]# unset A        #释放变量 
[root@AliYun ~]# echo $A        #再次调用变量A时,此时返回为空

[root@AliYun ~]#

4.3 变量的定义规则

虽然可以给变量(变量名)赋予任何值;但是,对于变量名需要符合以下要求:

1)变量名区分大小写
[root@AliYun ~]# A=hello
[root@AliYun ~]# a=world
[root@AliYun ~]# echo $A
hello
[root@AliYun ~]# echo $a
world
[root@AliYun ~]# 
2)变量名不能有特殊符号
[root@AliYun ~]# *A=hello
-bash: *A=hello: command not found
[root@AliYun ~]# ?A=hello
-bash: ?A=hello: command not found
[root@AliYun ~]# @A=hello
-bash: @A=hello: command not found

特别说明:对于有空格的字符串给变量赋值时,要用引号括起来
[root@AliYun ~]# A=hello world
-bash: world: command not found
[root@AliYun ~]# A="hello world"
[root@AliYun ~]# A='hello world'
3)变量名不能以数字开头
[root@AliYun ~]# 1A=hello
-bash: 1A=hello: command not found
[root@AliYun ~]# A1=hello
[root@AliYun ~]# 
4)等号两边不能有任何空格
[root@AliYun ~]# A =123
-bash: A: command not found
[root@AliYun ~]# A= 123
-bash: 123: command not found
[root@AliYun ~]# A = 123
-bash: A: command not found
[root@AliYun ~]# A=123
[root@AliYun ~]# echo $A
123
[root@AliYun ~]# 
5)变量名尽量做到见名知意
[root@AliYun ~]# NTP_IP=192.168.1.1
[root@AliYun ~]# DIR=/home/uyun
[root@AliYun ~]# TMP_FILE=/var/log/1.log

说明:一般变量名使用大写(小写也可以),不要同一个脚本中变量全是a,b,c等变量,这样不容易阅读与理解

4.4 变量的定义方式有哪些?

1)基本方式

直接赋值给一个变量

[root@AliYun ~]# A=20211219
[root@AliYun ~]# echo $A
20211219
[root@AliYun ~]# echo ${A:2:5}     #表示从A变量中第3个字符开始截取,截取5个字符
21121

说明:

变 量 名 和 变量名 和 {变量名}的异同:

相同点:都可以调用变量

不同点: 变 量 名 可 以 只 截 取 变 量 的 一 部 分 , 而 {变量名}可以只截取变量的一部分,而 变量名不可以

2)命令执行结果赋值给变量
[root@AliYun ~]# B=`date +%F`
[root@AliYun ~]# echo $B
2021-12-19
[root@AliYun ~]# C=$(uname -r)
[root@AliYun ~]# echo $C
4.18.0-193.el8.x86_64
3)交互式定义变量

**目的:**让用户自己给变量赋值,比较灵活
语法:read [选项] 变量名
常见选项:

选项释义
-p定义提示用户的信息
-n定义字符数(限制变量值的长度)
-s不显示(不显示用户输入的内容)
-t定义超时时间,默认单位为秒(限制用户输入变量值的超时时间)

举例说明:
用法1:用户自己定义变量值

[root@AliYun ~]# read name
chengs
[root@AliYun ~]# echo $name
chengs
[root@AliYun ~]# 
[root@AliYun ~]# read -p "Input your name:" name
Input your name:chengs
[root@AliYun ~]# echo $name
chengs
[root@AliYun ~]# 
[root@AliYun ~]# read -s -p "Input your password:" pass
Input your password:[root@AliYun ~]# echo $pass                #-s参数不显示输入的内容
123456
[root@AliYun ~]# 
[root@AliYun ~]# read -n 4 -p "Input your name:" name
Input your name:chen[root@AliYun ~]# echo $name                #超过4个字符自动终止输入,所以最后该变量的最终值为你输入的前4个字符
chen
[root@AliYun ~]# 
[root@AliYun ~]# read -t 3 -p "Input your name:" name
Input your name:chen[root@AliYun ~]# cheng
-bash: cheng: command not found
[root@AliYun ~]# echo $name

[root@AliYun ~]#                                    #此处超过3秒未回车,赋值失败,所以该变量值为空

用法2:变量值来自文件

[root@AliYun uyun]# cat 1.txt 
192.168.1.1 255.255.255.0
[root@AliYun uyun]# read -p "Input your IP and netmask:" ip mask <1.txt 
[root@AliYun uyun]# echo $ip
192.168.1.1
[root@AliYun uyun]# echo $mask
255.255.255.0
[root@AliYun uyun]# 
4)定义有类型的变量

目的:给变量做一些限制,固定变量的类型,比如:整形、只读

用法:declare 选项 变量名=变量值

常用选项:

选项释义举例
-i将变量看成整数declare -i A=123
-r定义只读变量declare -r B=hello
-a定义普通数组;查看普通数组
-A定义关联数组;查看关联数组
-X将变量通过环境导出declare -X AAA=123456等于export AAA=123456

举例说明:

[root@AliYun ~]# declare -i A=123
[root@AliYun ~]# echo $A
123
[root@AliYun ~]# A=hello
[root@AliYun ~]# echo $A
0
[root@AliYun shell]# declare -r A=hello    #定义变量只读,并赋予初始值
[root@AliYun shell]# echo $A
hello
[root@AliYun shell]# A=888                 #因为之前已经定义该变量为只读,s再次为该变量赋值时则报错
-bash: A: readonly variable
[root@AliYun shell]# 
如果需要重新定义该变量,则只能使用exit退出当前终端,重新定义

4.5 变量的分类

1)本地变量

本地变量:当前用户自定义的变量。当前进程中有效,其他进程及当前进程的子进程无效。

2)环境变量

环境变量:当前进程有效,并且能够被子进程调用

  • env 查看当前用户的环境变量

  • set 查询当前用户的所有比变量(临时变量与环境变量)

  • export 变量名=变量值 或者 变量名=变量值; export 变量名

[root@AliYun ~]# export A=hello
[root@AliYun ~]# env |grep ^A
A=hello
[root@AliYun ~]# 

永久生效

vim /etc/profile 或者 ~/.bashrc
export A=hello
或者
A=hello
3)全局变量
  • 全局变量:全局所有的用户和程序都能调用,且继承,新建的用户也默认能调用。

  • 解读相关配置文件

文件名说明备注
$HOME/.bashrc当前用户的bash信息,用户登录时读取定义别名、umask、函数等
$HOME/.bash_profile当前用户的环境变量,用户登录时读取
$HOME/.bash_logout当前用户退出当前shell时最后读取定义用户退出时执行的程序等
/etc/bashrc全局的bash信息,所有用户都生效
/etc/profile全局环境变量信息系统和所有用户都生效

说明:以上文件修改后,都需要重新source让其生效或者退出重新登录。

用户登录系统读取相关文件的顺序

  1. /etc/profile
  2. $HOME/.bash_profile
  3. $HOME/.bashrc
  4. /etc/bashrc
  5. $HOME/.bash_logout
4)系统变量
  • 系统变量(内置bash中变量):shell本身已经固定好了它的名字和作用
内置变量含义
$?上一条命令执行后返回的状态;状态值为0表示执行正常,非0表示执行异常或错误
$0当前执行的程序或脚本名
$#脚本后面接的参数的个数
$*脚本后面所有参数,参数当成一个整体输出,每一个变量参数之间以空格隔开
$@脚本后面所有参数,参数是独立的,也是全部输出
$1~$9脚本后面的位置参数,$1表示第1个位置参数,依次类推
10   {10}~ 10 {n}扩展位置参数,第10个位置变量必须用{}大括号括起来(2位数字以上括起来)
$$当前所在进程的进程号,如echo $$
$!后台运行的最后一个进程号(当前终端)
!$调用最后一条命令历史中的参数

如:

[root@AliYun ~]# ps
    PID TTY          TIME CMD
 728303 pts/0    00:00:00 bash
 729455 pts/0    00:00:00 ps
[root@AliYun ~]# ls
shell
[root@AliYun ~]# echo $?
0
[root@AliYun ~]# lll
-bash: lll: command not found
[root@AliYun ~]# echo $?
127
[root@AliYun ~]# 
#使用echo $? 查看上一条命令执行后的返回状态,如上所示,正常执行的命令,使用echo $?返回0,表示命令执行成功,上一条命令错误的时候,使用echo $?命令查看返回非0,表示命令执行错误

? 的 使 用 场 景 : 使 用 y u m − y i n s t a l l x x x 安 装 x x x 应 用 时 , 结 合 ?的使用场景:使用yum -y install xxx安装xxx应用时,结合 ?使使yumyinstallxxxxxx?可以查看xx应用是否安装成功

五、简单四则运算

算术运算:默认情况下,shell就只能支持简单的整数运算

运算内容:加(+)、减(-)、乘(*)、除(/)、求余(%)

5.1 四则运算符号

表达式举例
$(())echo $((1+1))
$[]echo $[10-5]
exprexpr 10/5
letn=1;let n+=1 等价于 let n=n+1

5.2 了解i++和++i

  • 对变量的值的影响
[root@AliYun ~]# i=1
[root@AliYun ~]# let i++
[root@AliYun ~]# echo $i
2
[root@AliYun ~]# j=1
[root@AliYun ~]# let ++j
[root@AliYun ~]# echo $j
2
[root@AliYun ~]# 
  • 对表达式的值的影响
[root@AliYun ~]# 
[root@AliYun ~]# unset i j
[root@AliYun ~]# i=1;j=1
[root@AliYun ~]# let x=i+j         ##先赋值,再运算
[root@AliYun ~]# let y=++j         ##先运算,再赋值
[root@AliYun ~]# echo $i
1
[root@AliYun ~]# echo $j
2
[root@AliYun ~]# echo $x
2
[root@AliYun ~]# echo $y
2
[root@AliYun ~]# 

六、条件判断与流程控制

  • 熟悉条件判断语句,如判断整数、判断字符串等

  • 熟悉流程控制语句基本语法,如if…else…

6.1 条件判断语法结构

思考:何为真(true)? 何为假(false)?

1 条件判断语法格式

  • 格式1:test条件表达式
  • 格式2:[条件表达式]
  • 格式3:[[条件表达式]]支持正则=~

特别说明:

1)[xx, 我两边都有空格, 一定要有空格]

2)[[xx, 我两边都有空格, 一定要有空格]]

3)更多判断,man test 去查看,很多的参数都用来进行条件判断

2 条件判断相关参数

问:你要判断什么?

答:我要判断文件类型,判断文件新旧,判断字符串是否相等,判断权限等等…

1)判断文件类型
判断参数含义
-e判断文件是否存在(任何类型文件)
-f判断文件是否存在并且是一个普通文件
-d判断文件是否存在并且是一个目录
-L判断文件是否存在并且是一个软连接文件
-b判断文件是否存在并且是一个块设备文件
-S判断文件是否存在并且是一个套接字文件

举例说明:

格式1:

[root@AliYun shell]# 
[root@AliYun shell]# touch file1
[root@AliYun shell]# echo hello > file2
[root@AliYun shell]# ll
total 4
-rw-r--r-- 1 root root 0 Jan 16 14:22 file1
-rw-r--r-- 1 root root 6 Jan 16 14:23 file2
[root@AliYun shell]# mkdir  dir1
[root@AliYun shell]# test -e ./file1     #执行判断,判断file1文件是否存在,但是此判断无输出结果
[root@AliYun shell]# echo $?             #查看上一条命令执行结果,0表示为“真”,文件存在
0
[root@AliYun shell]# 
[root@AliYun shell]# test -e ./test1
[root@AliYun shell]# echo $?             #查看上一条命令执行结果,1表示为“假”,文件不存在
1
[root@AliYun shell]# 

格式2:

[root@AliYun shell]# [ -d ./dir1 ];echo $?   #判断dir1目录是否存在,并且查看该判断的执行结果
0
[root@AliYun shell]# [ -d ./file1 ];echo $?  #判断file1目录是否存在,并且查看该判断的执行结果 
1                                            #file1是一个文件,不是目录,所以返回结果为1(假)
[root@AliYun shell]# 
[root@AliYun shell]# ln -s file1 test1      #创建一个软连接文件
[root@AliYun shell]# ll
total 8
drwxr-xr-x 2 root root 4096 Jan 16 14:24 dir1
-rw-r--r-- 1 root root    0 Jan 16 14:22 file1
-rw-r--r-- 1 root root    6 Jan 16 14:23 file2
lrwxrwxrwx 1 root root    5 Jan 16 14:35 test1 -> file1
[root@AliYun shell]# [ -L ./test1 ];echo $?   #判断test1软连接文件是否存在,并且查看返回结果
0
[root@AliYun shell]#

注意:

[root@AliYun shell]# rm -rf file1           
[root@AliYun shell]# [ -L ./test1 ];echo $?   
0
[root@AliYun shell]# 

此时使用rm -rf命令删除了fiel1文件,但执行软连接文件是否存在的判断语句时,该判断返回结果仍然为“真”,因为该语句只能判断软连接文件是否存在,不能判断软连接文件是否有效。

[root@AliYun shell]# [[ -f ./file2 ]];echo $?  #判断file2是否是一个普通文件,并且查看返回结果
0
[root@AliYun shell]# ll
drwxr-xr-x 2 root root 4096 Jan 16 14:24 dir1
-rw-r--r-- 1 root root    6 Jan 16 14:23 file2
lrwxrwxrwx 1 root root    5 Jan 16 14:35 test1 -> file1

[root@AliYun shell]# [[ -f ./test1 ]];echo $?
1
[root@AliYun shell]# 
[root@AliYun shell]# [ ! -d ./dir1 ];echo $?   #判断dir1目录是否不存在,并查看返回结果
1                           #因为该目录存在,所以实际返回结果为“假” 
[root@AliYun shell]#
[root@AliYun shell]# [ ! -d ./dir2 ];echo $?
0                           #dir2目录不存在,所以返回为“真”
[root@AliYun shell]# 
2)判断文件权限
判断参数含义
-r当前用户对其是否可读
-w当前用户对其是否可写
-x当前用户对其是否可执行
-u是否有suid,高级权限冒险位
-g是否sgid,高级权限强制位
-k是否有t位,高级权限粘滞位

举例说明:

[root@AliYun shell]# ll    #前提条件
total 12
-rwxr-xr-x 1 root root   34 Jan 16 16:02 1.sh
drwxr-xr-x 2 root root 4096 Jan 16 14:24 dir1
-rw-r--r-- 1 root root    6 Jan 16 14:23 file2
lrwxrwxrwx 1 root root    5 Jan 16 14:35 test1 -> file1
[root@AliYun shell]# 

格式1:

[root@AliYun shell]# test -r 1.sh;echo $?
0
[root@AliYun shell]# test -w 1.sh;echo $?
0
[root@AliYun shell]# test -x 1.sh;echo $?
0

格式2:

[root@AliYun shell]# [ -r ./1.sh ];echo $?
0
[root@AliYun shell]# [ -w ./1.sh ];echo $?
0
[root@AliYun shell]# [ -x ./1.sh ];echo $?
0
[root@AliYun shell]# 
[uyun@AliYun shell]$ test -r 1.sh;echo $?
0
[uyun@AliYun shell]$ test -w 1.sh;echo $?
1
[uyun@AliYun shell]$ [ -x ./1.sh ];echo $?
0
[uyun@AliYun shell]$ 
3)判断文件新旧

说明:这里的新旧指的是文件的修改时间

判断参数含义
file1 -nt file2比较file1是否比file2新
file1 -ot file2比较file1是否比file2旧
file1 -ef file2比较是否为同一个文件,或者用于判断硬连接,是否指向同一个inode

举例说明:

[root@AliYun shell]# ll      #前提条件
total 12
-rwxr-xr-x 1 root root   34 Jan 16 16:02 1.sh
drwxr-xr-x 2 root root 4096 Jan 16 14:24 dir1
-rw-r--r-- 1 root root    0 Jan 16 16:18 file1
-rw-r--r-- 1 root root    6 Jan 16 14:23 file2
lrwxrwxrwx 1 root root    5 Jan 16 14:35 test1 -> file1
[root@AliYun shell]# 
[root@AliYun shell]# test file1 -nt file2;echo $?   #比较file1是否比file2新
0
[root@AliYun shell]# test file2 -nt file1;echo $?   #比较file2是否比file1新
1
[root@AliYun shell]# test file1 -ot file2;echo $?   #比较file1是否比file2老
1
[root@AliYun shell]#
[root@AliYun shell]# ll     #前提条件
total 16
-rwxr-xr-x 1 root root   34 Jan 16 16:02 1.sh
drwxr-xr-x 2 root root 4096 Jan 16 14:24 dir1
-rw-r--r-- 1 root root    6 Jan 16 16:25 file1
-rw-r--r-- 1 root root   19 Jan 16 16:26 file2
lrwxrwxrwx 1 root root    5 Jan 16 14:35 test1 -> file1
[root@AliYun shell]# cat file1
hello
[root@AliYun shell]# cat file2
hello
this is test
[root@AliYun shell]# 
[root@AliYun shell]# test file1 -ef file2;echo $?    #比较file1和file2是否是同一个文件
1                                                    #此处不比较文件中的具体内容,只对文件本身进行比较,fle1和file2是不同的文件,所以比较结果返回为1(假)
[root@AliYun shell]# 
4)整数判断
判断参数含义
-eq相等
-ne不等
-gt大于
-lt小于
-ge大于等于
-le小于等于

举例说明:

[root@AliYun shell]# 
[root@AliYun shell]# i=1
[root@AliYun shell]# j=1
[root@AliYun shell]# test $i -eq $j;echo $?
0
[root@AliYun shell]#
[root@AliYun shell]# 
[root@AliYun shell]# i=2
[root@AliYun shell]# j=3
[root@AliYun shell]# test $i -ne $j;echo $?
0
[root@AliYun shell]# test $i -gt $j;echo $?
1
[root@AliYun shell]# test $i -lt $j;echo $?
0
[root@AliYun shell]# test $i -ge $j;echo $?
1
[root@AliYun shell]# test $i -le $j;echo $?
0
[root@AliYun shell]# 
5)判断字符串

此判断在shell脚本中常用

判断参数含义
-z判断是否为字符串,字符串长度为0,则成立
-n判断是否为非空字符串,字符串长度不为0,则成立
string1 =string2判断字符串是否相等
string1 !=string2判断字符串是否不相等

举例说明:

[root@AliYun shell]# 
[root@AliYun shell]# test -z "hello world";echo $?  
1
[root@AliYun shell]# test -z "";echo $?
0
[root@AliYun shell]# test -z " ";echo $?    #特别注意,这里的双引号中存在一个空格,空格不为空,所以返回为1(不为空)
1
[root@AliYun shell]# 
[root@AliYun shell]# test -n "hello world";echo $?
0
[root@AliYun shell]# test -n "";echo $?
1
[root@AliYun shell]# 
[root@AliYun shell]# test "hello world" = "helloworld";echo $?   #判断hello world是否等于helloworld,结果不等,所以返回1(假)
1
[root@AliYun shell]# test "hello world" != "helloworld";echo $?  #判断hello world是否不等于helloworld,结果不等,所以返回0(真)
0
[root@AliYun shell]# 
6)多重条件判断
判断符号含义举例
-a 和 &&逻辑与[ 1 -eq 1 -a 1 -ne 0 ] [ 1 -eq 1 ] && [ 1 -ne 0 ]
-o 和 ||逻辑或[ 1 -eq 1 -o 1 -ne 1 ] [ 1 -eq 1 ]

特别说明:

&& 前面的表达式为,才会执行后面的代码

|| 前面的表达式为,才会执行后面的代码

用于分割命令或表达式

思考:为何下面的语句1返回报错?

[root@AliYun shell]# ll            #前提条件
total 24
-rwxr-xr-x 1 root root  109 Jan 16 18:11 1.sh
-rw-r--r-- 1 root root    1 Jan 16 17:05 1.txt
-rw-r--r-- 1 root root    1 Jan 16 17:05 2.txt
drwxr-xr-x 2 root root 4096 Jan 16 14:24 dir1
-rw-r--r-- 1 root root   19 Jan 16 16:26 file2
-rw-r--r-- 1 root root    2 Jan 16 18:07 i
lrwxrwxrwx 1 root root    5 Jan 16 14:35 test1 -> file1
[root@AliYun shell]# [ -e test1 && -L test1 ];echo $?     #语句1
-bash: [: missing `]'
2
[root@AliYun shell]# [ -e test1 -a -L test1 ];echo $?     #语句2 
1
[root@AliYun shell]# 

举例说明:

  • 数值比较
[root@AliYun shell]# [ $(id -u) -eq 0 ] && echo "root"  #id -u取的是用户id,用户id为0则表示该用户为root用户,结合整个语句,此处的用意就是:如果是root用户就打印root字符
root
[root@AliYun shell]# 
#切换非root账户,再次执行该判断,条件不成立,则不会执行&&后面的命令
[chen@AliYun shell]$ [ $(id -u) -eq 0 ] && echo "root"
[chen@AliYun shell]$
[chen@AliYun shell]$ [ $(id -u) -eq 0 ] || echo "is not root"
is not root            #非管理员账户执行该语句,前半段返回结果为“假”,条件成立,继续执行后半部分命令,所以此处打印出了is not root
[chen@AliYun shell]$
[root@AliYun ~]# 
[root@AliYun ~]# [ $(id -u) -eq 0 ] && echo "root" || echo "is not root"     #多个运算符在一起时,运算符之间从左往右依次判断
root
[root@AliYun ~]# su chen
[chen@AliYun root]$ [ $(id -u) -eq 0 ] && echo "root" || echo "is not root"   
is not root
[chen@AliYun root]$ 

思考:

[chen@AliYun root]$ [ 1 -eq 2 ] && echo ABC || echo DEF && echo HIJ

返回结果为多少?

  • 类C风格的数值比较

注意:在(())中,=表示赋值;==表示判断

[root@AliYun ~]# ((1==2));echo $?
1
[root@AliYun ~]# ((1<2));echo $?
0
[root@AliYun ~]# ((2>=1));echo $?
0
[root@AliYun ~]# ((2!=1));echo $?
0
[root@AliYun ~]# ((`id -u` ==0));echo $?
0
[root@AliYun ~]# ((a=123));echo $a
123
[root@AliYun ~]# unset a
[root@AliYun ~]# ((a==123));echo $?
1
[root@AliYun ~]#
  • 字符串比较

    注意:双引号括起来,看作是一个整体;= 和 == 在 [ 字符串 ] 比较中都表示判断

[root@AliYun ~]# A=hello;B=world;[ "$A" = "$B" ];echo $?
1
[root@AliYun ~]# 
[root@AliYun ~]# A=
[root@AliYun ~]# echo $A

[root@AliYun ~]# test $A = hello
-bash: test: =: unary operator expected
[root@AliYun ~]# test "$A" = "hello"
[root@AliYun ~]# echo $?
1
[root@AliYun ~]#

思考:[] 和 [[]] 有什么区别?

[root@AliYun shell]# A=
[root@AliYun shell]# [ "$A" = "hello" ];echo $?
1
[root@AliYun shell]# [[ $A = hello ]];echo $?
1
[root@AliYun shell]# [[ "$A" = "hello" ]];echo $?
1
[root@AliYun shell]# 
[root@AliYun shell]# [ -e test1 -a -L test1 ];echo $?
1
[root@AliYun shell]# touch file1
[root@AliYun shell]# [ -e test1 -a -L test1 ];echo $?
0
[root@AliYun shell]# 
[root@AliYun shell]# [ -e test1 && -L test1 ];echo $?
-bash: [: missing `]'
2
[root@AliYun shell]# [[ -e test1 && -L test1 ]];echo $?
0
[root@AliYun shell]# ll
7)逻辑运算符总结

1)符号;和&&和||都可以用来分割命令或者表达式

2)分行 (😉 完全不考虑前面的语句是否正确执行,都会执行;号后面的内容

3)&&符号,需要考虑&&前面的语句的正确性,前面语句正确执行才会执行&&后面的内容;反之亦然

4)||符号,需要考虑||前面的语句的非正确性,前面语句执行错误才会执行||后面的内容;反之亦然

5)如果&&和||一起出现,从左往右依次看,按照以上原则

6.2 流程控制语句

关键词: 选择(shell需要学习的内容很多,我该如何学好shell语言)

  1. 基本语法结构
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
学习Shell命令时,以下是一些重要的注意事项和学习建议: 1. 基本语法:Shell命令通常由命令名称和参数组成。命令名称是要执行的操作,而参数则提供了命令所需的信息。了解Shell命令的基本语法是学习的第一步。 2. 命令帮助:大多数Shell都提供了内置的命令帮助功能。通过使用命令后跟`--help`或`-h`选项,或者使用`man`命令(例如`man ls`)来获取有关特定命令的详细信息。 3. 常用命令:有一些常见的Shell命令对于日常使用非常有用。这些包括`cd`(更改目录)、`ls`(列出目录内容)、`mkdir`(创建目录)、`rm`(删除文件或目录)等。逐步学习和掌握这些命令是很重要的。 4. 管道和重定向:Shell命令非常强大,可以通过管道和重定向符号将多个命令组合在一起。了解如何使用管道(`|`)将一个命令的输出作为另一个命令的输入,并使用重定向符号(`>`、`>>`、`<`)来控制输入和输出。 5. 脚本编写:Shell脚本是一种将多个命令组合在一起以自动化任务的方法。学习如何编写简单的Shell脚本可以提高工作效率。 6. 实践和练习:最重要的是进行实践和练习。尝试使用不同的Shell命令来完成各种任务,并在实际场景中应用所学知识。 记住,Shell命令的学习是一个逐步的过程。开始时可能会有些困惑,但随着实践和经验的积累,你会变得越来越熟练。希望这些提示对你有帮助!如有任何具体问题,随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值