linux系统是如何操作计算机硬件CPU,内存,磁盘,显示器等?

使用linux的内核操作计算机的硬件

Shell介绍

通过编写Shell命令发送给linux内核去执行, 操作就是计算机硬件. 所以Shell命令是用户操作计算机硬件的桥梁。

Shell是命令, 类似于windows系统Dos命令

Shell是一个门程序设计语言, Shell里面含有变量, 函数, 逻辑控制语句等等

Shell脚本

通过Shell命令或程序编程语言编写的Shell文本文件, 这就是Shell脚本 , 也叫Shell程序

为什么学习Shell脚本?

通过Shell命令与编程语言来提高linux系统的管理工作效率

Shell的运行过程

当用户下达指令给该操作系统的时候,实际上是把指令告诉shell,经过shell解释,处理后让内核做出相应的动作。 系统的回应和输出的信息也由shell处理,然后显示在用户的屏幕上。

Shell解析器

查看linux系统centos支持的shell解析器

cat /etc/shells

效果:

解析器类型:

解析器类型介绍
/bin/shBourne Shell,是UNIX最初使用的shell;
/bin/bashBourne Again Shell它是Bourne Shell的扩展,简称bash,是LinuxOS默认shell,有灵活和强大的编辑接口,同时又很友好的用户界面,交互性很强;
/sbin/nologin未登录解析器, shell设置为/sbin/nologin 是用于控制用户禁止登陆系统的, 有时候有些服务,比如邮件服务,大部分都是用来接收主机的邮件而已,并不需要登陆
/bin/dashdash(Debian Almquist Shell),也是一种 Unix shell。它比 Bash 小,只需要较少的磁盘空间,但是它的对话性功能也较少,交互性较差。
/bin/cshC Shell是C语言风格Shell
/bin/tcsh是C Shell的一个扩展版本。

Centos默认的解析器是bash

echo $SHELL

含义: 打印输出当前系统环境使用的Shell解析器类型

echo 用于打印输出数据到终端

$SHELL 是全局共享的读取解析器类型环境变量, 全局环境变量时所有的Shell程序都可以读取的变量,

效果

Shell脚本编写规范

shell脚本文件是一个文本文件,后缀名建议使用 .sh 结尾

首行规范

首行需要设置Shell解析器的类型,语法为 #!/bin/bash

主要是设置当前的Shell脚本文件采用bash解析器来运行脚本代码

注释格式

单行注释: #注释内容

多行注释:

:<<!
# 注释内容
# 注释内容
!

helloworld

touch helloworld.sh
vim helloworld.sh

#写入shell脚本内容

#!/bin/bash
echo "hello world"

#保存退出
#按esc,输入:wq

#查看内容写入成功否
cat helloworld.sh

脚本文件执行

常用的三种执行方式

  1. sh解析器执行方式
  2. bash解析器执行方式
  3. 仅路径执行方式

sh解析器执行方式

利用sh命令执行脚本文件,本质:使用Shell解析器运行脚本文件。

语法:sh 脚本文件

eg:sh helloworld.sh

bash解析器执行方式

利用bash命令执行脚本文件,本质:使用Shell解析器运行脚本文件。(概念跟sh一样的)

语法:bash 脚本文件

仅路径执行方式

执行当前目录下的脚本文件

注意:脚本文件自己执行需要具有可执行权限,否则无法执行

语法:./脚本文件

eg:./helloworld.sh ,会提示权限不够。

给所有用户添加 helloworld.sh 可执行权限:chmod a+x helloworld.sh

三种方式的区别

sh或bash执行脚本文件方式是直接使用Shell解析器运行脚本文件,不需要可执行权限

仅路径方式是执行脚本文件自己,需要可执行权限

Shell脚本多命令处理

就是在Shell脚本文件中编写多个Shell命令

案例需求

已知目录 /root/xn2001 目录,执行 batch.sh 脚本,实现在 /root/xn2001/ 目录下创建一个 one.txt,在 one.txt 文件中增加内容 "Hello Shell"

步骤分析

使用 mkdir 创建 /root/xn2001 目录

创建脚本文件 batch.sh

编辑命令

  1. 创建 one.txt
  2. 输出数据 "Hello Shell"one.txt 文件中

输出数据到文件的命令:

数据 >> 文件

这是Linux中重定向内容的知识

执行脚本文件

实现案例

mkdir /root/xn2001
cd /xn201
touch batch.sh
vim batch.sh
#!/bin/bash
touch one.txt
echo "Hello Shell" >> one.txt
ll
sh batch.sh
cat batch.sh
cat one.txt

可以看到 one.txt 文件内就有了 Hello Shell

Shell环境变量

变量用于存储管理临时的数据,这些数据都是在运行内存中的。

变量类型:

  1. 系统环境变量
  2. 自定义变量
  3. 特殊符号变量

系统环境变量

系统提供的共享变量,是Linux系统加载Shell配置文件中定义的变量,共享给所有的 Shell程序 使用。

Shell配置文件分类

全局配置文件

/etc/profile

/etc/profile.d/*.sh

/etc/bashrc

个人配置文件

/当前用户/.bash_profile

/当前用户/.bashrc

一般情况下,我们都是直接针对全局配置文件进行操作。

环境变量分类

在Linux系统中,环境变量按照其作用范围大致可以分为 系统级环境变量用户级环境变量

系统级环境变量:Shell环境加载全局配置文件中的变量共享给所有用户所有Shell程序使用,全局共享

用户级环境变量:Shell环境加载个人配置文件中的变量共享给当前用户的Shell程序使用,仅当前登录用户使用

查看环境变量

查看Shell系统环境变量

命令:env

查看Shell变量(系统环境变量+自定义变量+函数)

命令:set

常用系统环境变量

变量名称含义
PATH与Windows环境变量PATH功能一样,设置命令的搜索路径,以冒号为分割
HOME当前用户主目录:/root
SHELL当前shell解析器类型:/bin/bash
HISTFILE显示当前用户执行命令的历史列表文件:/root/.bash_history
PWD显示当前所在路径:/root
OLDPWD显示之前的路径
HOSTNAME显示当前的主机名
HOSTTYPE显示主机的架构,x86_64
LANG设置当前系统语言环境,如zh_CN.UTF-8

环境变量输出

echo $PSTH
echo $PWD
echo $LANG

Shell自定义变量

就是自己定义的变量

分类:

  1. 自定义局部变量
  2. 自定义常量
  3. 自定义全局变量

自定义局部变量

就是定义在一个脚本文件中的变量,只能在这个脚本文件中使用的变量。

定义语法: var_name=value

定义规则:

  1. 变量名称可以有字母,数字和下划线组成,但不能以数字开头。
  2. 等号两侧不能有空格。
  3. 在bash环境中,变量的默认类型都是字符串,无法直接进行数值运算。
  4. 变量的值如果有空格,必须使用双引号括起来。
  5. 不能使用Shell的关键字作为变量名称。

查询变量值语法:

  1. 直接使用变量名查询,$变量名
  2. 使用花括号查询,${变量名}

推荐大家使用花括号才是编程的好习惯。

演示:

[root@localhost ~]# name=xn2001
[root@localhost ~]# age=14
[root@localhost ~]# echo $name
xn2001
[root@localhost ~]# echo $age
14
[root@localhost ~]# echo ${name}钟小湖
xn2001钟小湖

变量删除

unset var_name

自定义常量

就是变量设置值以后不可以修改的变量就叫常量,也叫只读变量

语法:readonly var_name

演示:

[root@localhost ~]# sex=male
[root@localhost ~]# sex=123
[root@localhost ~]# sex=male
[root@localhost ~]# readonly sex
[root@localhost ~]# sex=123
-bash: sex: 只读变量
[root@localhost ~]# 

自定义全局变量

父子Shell环境介绍

例如:有2个Shell脚本文件,A.sh 和 B.sh

在 A.sh 脚本文件中执行了 B.sh 脚本文件,那么 A.sh 就是父Shell环境,B.sh 就是子Shell环境。

自定义全局变量介绍

就是在当前脚本文件中定义全局变量,这个全局变量可以在当前的Shell环境与子Shell环境中都可以使用。

自定义全局变量语法

export var_name var_name2

案例需求

测试全局变量在子Shell中是否可用,在父Shell中是否可用。

实现步骤

  1. 创建2个脚本文件 demo2.sh 和demo3.sh
  2. 编辑 demo2.sh -> 定义 VAR,执行 demo3.sh
  3. 编辑 demo3.sh -> 输出全局变量 VAR
  4. 执行 demo2.sh
touch demo2.sh demo3.sh
vim demo2.sh
#demo2.sh内容如下
#!/bin/bash
export VAR=xn2001
sh demo3.sh
#结束

vim demo3.sh
#demo3.sh内容如下
#!/bin/bash
echo demo3.sh文件输出变量VAR:${VAR}
#结束

[root@localhost ~]# sh demo2.sh
demo3.sh文件输出变量VAR:xn2001

Shell特殊变量

目标:能够说出常用的特殊变量有哪些

$n

用于接收脚本文件执行时传入的参数

$0:用于获取当前脚本文件名称

$1~$9,代表获取第1输入参数到第9个输入参数

第10个参数以上获取参数的格式:${数字},否则无法获取。

执行脚本文件传入参数语法

sh 脚本文件 输入参数1 输入参数2 ...

案例需求:

创建脚本文件demo4.sh,并在脚本文件内部打印脚本文件名字、第一个输入参数、第二个输入参数

touch demo4.sh
vim demo4.sh
#内容
#!/bin/bash
echo $0
echo $1
echo $2
#结束
[root@localhost ~]# sh demo4.sh xn2001 18
demo4.sh
xn2001
18

$

获取所有输入参数的个数

案例需求:

在 demo4.sh 中输出输入参数的个数

vim demo4.sh
#添加内容
echo "输入参数的个数为:"$#
#结束
[root@localhost ~]# sh demo4.sh xn2001 18
demo4.sh
xn2001
18
输入参数的个数为:2

$*、$@

都是获取所有的输入参数,用于以后输出所有参数

区别

不使用双引号括起来,没有区别。 -> 返回格式为:$1 $2 $3 ...

使用双引号括起来,返回格式有所区别。

  1. "$*" 获取的所有参数拼接为一个字符串,格式为:"$1 $2 ... $n"
  2. "$@" 获取一组参数列表对象,格式为:"$1" "$2" "$3" ...
使用循环打印所有输入参数可以看出区别

循环语法:

for var in 列表变量
do        #循环开始
    命令    #循环体
done       #循环结束

案例需求:

在 demo4.sh 中循环打印输出所有输入参数,体验 $*$@ 的区别

vim demo4.sh
#内容
#!/bin/bash
echo '使用$*直接输出:'$*
echo '使用$@直接输出:'$@
echo '循环遍历输出$*所有参数'
for item in "$*"
do
  echo $item
done
echo '循环遍历输出$@所有参数'
for item in "$@"
do
  echo $item
done
#结束
[root@localhost ~]# sh demo4.sh xn2001 18
使用$*直接输出:xn2001 18
使用$@直接输出:xn2001 18
循环遍历输出$*所有参数
xn2001 18
循环遍历输出$@所有参数
xn2001
18
小妙招:在vim中怎么复制呢,比如我们光标到某一行,按esc切换回命令行状态,输入你要复制的行数,比如5行就输入5,然后按两次y,光标移动到最后,输入p即可。

$?

用于获取上一个Shell命令的退出状态码,或者是函数的返回值。

每个Shell命令的执行都有一个返回值,这个返回值用于命令执行是否成功

一般来说,返回0代表执行成功,非0代表执行失败。

演示:

执行一个成功命令

[root@localhost ~]# echo "hello"
hello
[root@localhost ~]# echo $?
0

执行一个失败命令

[root@localhost ~]# ee
-bash: ee: 未找到命令
[root@localhost ~]# echo $?
127

$$

用于获取当前Shell环境的进程ID号

查看当前Shell环境进程编号

ps -aux|grep bash
[root@localhost ~]# ps -aux | grep bash
root       1225  0.0  0.2 115544  2088 pts/0    Ss   14:16   0:00 -bash
root       1692  0.0  0.0 112824   980 pts/0    S+   17:31   0:00 grep --color=auto bash
[root@localhost ~]# echo $$
1225

Shell环境变量深入探讨

/etc/profile

当用户进入Shell环境初始化的时候会加载全局配置文件 /etc/profile 里面的环境变量,供有所有Shell程序使用。

以后只要是所有的Shell程序或命令使用的变量,就可以定义在这个文件中。

案例需求:

/etc/profile 定义存储自定义系统级环境变量数据

创建环境变量

编辑 /etc/profile 全局配置文件

重载配置文件,因为配置文件修改后要立刻加载里面的数据就需要重载。 -> source /etc/profile

在Shell环境中读取系统级环境变量VAR1

小技巧,在vim中,按下大写G(直接shift+g)直接跳到文件内容的末尾,按下gg跳回文件首行
在 /etc/profile 文件尾行添加
export VAR1=我是钟小湖

source /etc/profile
echo $VAR1

加载流程原理

用户进入Linux系统就会初始化Shell环境,这个环境会加载全局配置文件和用户个人配置文件中环境变量,每个脚本文件都有自己的Shell环境。

交互式与非交互式Shell

交互式Shell

与用户进行交互,互动。效果就是用户输入一个命令,Shell环境立刻反馈响应。

非交互式Shell

不需要用户参与就可以执行多个命令,比如一个脚本文件含有多个命令,直接执行并给出结果。

登录与非登录Shell环境

Shell登录环境

需要用户名\密码登录的Shell环境

Shell非登录环境

不需要用户名\密码进入的Shell环境或执行脚本文件

注意:他们的环境变量加载流程不一样。

Shell初始化环境变量过程执行文件顺序
Shell登录环境初始化过程/etc/profile -> /etc/profile.d/*.sh -> ~/.bash_profile -> ~/.bashrc -> /etc/bashrc
Shell非登录环境初始化过程~/.bashrc -> /etc/bashrc -> /etc/profile.d/*.sh

Shell环境类型

使用 $0 识别环境语法

语法:echo $0

输出 -bash 代表:shell登录环境

输出 bash 代表:shell非登录环境

注意:这个 $0 环境变量如果用在子Shell中(Shell脚本文件),输出Shell脚本本身的文件名

bash :用于切换为Shell非登录环境

[root@localhost ~]# echo $0
-bash
[root@localhost ~]# bash
[root@localhost ~]# echo $0
bash

Shell字符串变量

字符串三种格式

单引号方式

双引号方式(推荐)

不使用引号方式

三种格式区别

使用单引号 '' 的字符串:

任何字符都会原样输出,在拼接字符串中使用变量是无效的。

[root@localhost ~]# var1=666
[root@localhost ~]# echo 'abc${var1}'
abc${var1}
[root@localhost ~]# echo 'abc'${var1}
abc666
[root@localhost ~]#

使用双引号 "" 的字符串:

其中包含了变量,那么该变量会解析得到值,而不是原样输出。

字符串中还可以出现双引号的字字符串,但是需要转义。

[root@localhost ~]# var2=乐心湖你好
[root@localhost ~]# echo "2020年${var2}"
2020年乐心湖你好
[root@localhost ~]# echo "2020年\"${var2}\""
2020年"乐心湖你好"

不被引号包围的字符串

不被引号包围的字符串中出现变量时也会被解析,这一点和双引号 "" 一样。

但是变量后面中不能再出现空格,否则无法解析,会被当做其他指令进行。

[root@localhost ~]# var3=2020年,${var2},  祝你快乐
-bash: 祝你快乐: 未找到命令
[root@localhost ~]# var3=2020年,${var2},祝你快乐
[root@localhost ~]# echo ${var3}
2020年,乐心湖你好,祝你快乐
[root@localhost ~]# var3="2020年, 哈哈 , ${var2}"
[root@localhost ~]# echo ${var3}
2020年, 哈哈 , 乐心湖你好

字符串截取

语法作用
${变量名:start:length}从 string 字符串的左边第 start 个字符开始,向右截取 length 个字符。start 从0开始计数。
${变量名:start}从 string 字符串的左边第 start 个字符开始截取到最后。
${变量名:0-start:length}从 string 字符串的右边第 start 个字符开始,向右截取 length 个字符。start 从1开始计数。
${变量名#*chars}从 string 字符串的左边第一次出现 chars 的位置开始,截取 chars 右边的所有字符。
${变量名##*chars}从 string 字符串的左边最后一次出现 chars 的位置开始,截取 chars 右边的所有字符。
${变量名%chars*}从 string 字符串的右边第一次出现 chars 的位置开始,截取 chars 左边的所有字符。
${变量名%%chars*}从 string 字符串的左边最后一次出现 chars 的位置开始,截取 chars 左边的所有字符。

案例需求演示:

[root@localhost ~]# touch demo9.sh
[root@localhost ~]# vim demo9.sh
#内容
var="weclome to shell from xn2001"
echo ${var}
# 从左侧0开始,向左截取2个字符
echo "从左侧0开始,向左截取2个字符: ${var:0:2}"
# 从左侧第11个开始,向左截取所有字符
echo "从左侧第11个开始,向左截取所有字符: ${var:11}"
# 从右侧第5个开始,向右截取2个字符
echo "从右侧第5个开始,向右截取2个字符: ${var:0-5:2}"
# 截取左边第一个出现字符e右边的所有字符
echo "截取左边第一个出现字符e右边的所有字符: ${var#*e}"
# 截取左边最后一次出现e右边的所有字符
echo "截取左边最后一次出现e右边的所有字符: ${var##*e}"
# 截取右边第一次出现字符e左边的所有字符
echo "截取右边第一次出现字符e左边的所有字符: ${var%e*}"
# 截取右边最后一次出现字符e左右的所有字符
echo "截取右边最后一次出现字符e左右的所有字符: ${var%%e*}"
#结束

[root@localhost ~]# sh demo9.sh
weclome to shell from xn2001
从左侧0开始,向左截取2个字符: we
从左侧第11个开始,向左截取所有字符: shell from xn2001
从右侧第5个开始,向右截取2个字符: n2
截取左边第一个出现字符e右边的所有字符: clome to shell from xn2001
截取左边最后一次出现e右边的所有字符: ll from xn2001
截取右边第一次出现字符e左边的所有字符: weclome to sh
截取右边最后一次出现字符e左右的所有字符: w

Shell数组

Shell 支持数组(Array),数组是若干数据的集合,其中的每一份数据都称为数组的元素。

注意: Bash Shell 只支持一维数组,不支持多维数组。

数组的定义

语法

在Shell中,用括号 () 来表示数组,数组元素之间用空格来分割。

array_name=(item1 item2 ...) #方式1
array_name=([索引下标]=item1 [索引下标]=item2 ...) #方式2,可以自定义下标
[root@localhost ~]# arr1=(hello "乐心湖" "新年快乐" 18)
[root@localhost ~]# arr2=([8]hello [2]="乐心湖" [10]="新年快乐" [5]=18)

数组的获取

通过下标获取元素值,index从0开始 :${arr[index]}

获取值同时复制给其他变量:item=${arr[index]}

使用 @ 或者 * 可以获取数组的所有元素:${arr[@]}${arr[*]}

使用 # 获取数组的长度或个数:${#arr[@]}${#arr[*]}

获取数组指定元素的字符程度:${#arr[索引]}

[root@localhost ~]# arr1=(hello "乐心湖" "新年快乐" 18)
[root@localhost ~]# arr2=([8]hello [2]="乐心湖" [10]="新年快乐" [5]=18)
[root@localhost ~]# echo ${arr1[2]}
新年快乐
[root@localhost ~]# item=${arr1[1]}
[root@localhost ~]# echo ${item}
乐心湖
[root@localhost ~]# echo ${arr1[@]}
hello 乐心湖 新年快乐 18
[root@localhost ~]# echo ${arr1[*]}
hello 乐心湖 新年快乐 18
[root@localhost ~]# echo ${#arr1[@]}
4
[root@localhost ~]# echo ${#arr1[*]}
4
[root@localhost ~]# echo ${#arr1[0]}
5

数组的拼接

就是将两个数组拼接成一个数组

语法:

使用 @# 获取数组所有元素之后进行拼接

arr_new=(${array1[@]} ${array2[@]} ...)
arr_new=(${array1[*]} ${array2[*]} ...)

演示:

[root@localhost ~]# arr3=(${arr1[@]} ${arr2[@]})
[root@localhost ~]# echo ${arr3[@]}
hello 乐心湖 新年快乐 18 [8]hello 乐心湖 18 新年快乐

数组的删除

删除数组指定元素

unset array_name[index]

删除整个数组

unset array_name

Shell内置命令

Shell 内置命令,就是由 Bash Shell 自身提供的命令,而不是文件系统中的可执行脚本文件。使用 type 来确定一个命令是否为内置命令。

type cd

[root@localhost ~]# type cd
cd 是 shell 内嵌 #cd是内嵌命令
[root@localhost ~]# type ip
ip 是 /usr/sbin/ip #ip是可执行文件

通常来说,内置命令会比外置命令执行得更快,执行外部命令时不但会粗发磁盘 I/O ,还需要 fork 出一个单独的进程来执行,执行完成后再退出。而执行内置命令相当于调用当前 Shell 进程的一个函数,还是在当前 Shell 环境进程内,减少了上下文切换。

alias设置别名

用于给命令设置别名

好处:可以将经常操作比较复杂的命令进行设置别名,通过别名的操作提高工作效率。

若该命令且不带任何参数,则显示所有当前 Shell 进程中的所有别名列表。

[root@localhost ~]# alias
alias cp='cp -i'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l.='ls -d .* --color=auto'
alias ll='ls -l --color=auto'
alias ls='ls --color=auto'
alias mv='mv -i'
alias rm='rm -i'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'

这些都是系统内置的别名。就像 ll 是别名,ls -l 才是真正的命令。

语法:

alias 别名=""

这里单引号和双引号都是可以的。

例如:我们对命令 ps -aux 设置一个简单的别名

[root@localhost ~]# alias psl='ps -aux'
[root@localhost ~]# psl

unalias删除别名

删除指定的别名

unalias 别名

删除当前Shell环境中所有的别名

unalias -a

以上2种方式删除都是临时删除当前Shell的别名,如果要永久删除必须去配置文件中手动删除。

echo输出字符串

echo 是一个Shell内置命令,用于在终端输出字符串,并在最后默认加上换行符。

默认换行语法:echo 字符串

不换行语法:echo -n 字符串

输出转义字符:echo -e '字符串中含有转义字符'

read读取控制台输入

read 是 Shell 内置命令,用于从标准输入中读取数据并赋值给变量,如果没有进行重定向,默认就是从终端控制台读取用户输入的数据;如果进行重定向,就可以从文件中读取数据。后面会详细介绍Shell重定向。

语法:

read [-options] [var1 var2 ...]

options 表示选项,如下表所示:

var 用来存储数据的变量,可以有一个也可以多个。

optionsvar 都是可选的,如果没有提供变量名,那么读取的数据将存放到环境变量 REPLY 变量中。

$REPLY 保存read最后一个读入命令的数据。

[root@localhost ~]# read
123
[root@localhost ~]# echo $REPLY
123
[root@localhost ~]# read name
钟小湖
[root@localhost ~]# echo ${name}
钟小湖
选项说明
-a array把读取的数据赋值给数组 array,从下标0开始。
-d delimiter用字符串 delimiter 指定读取结束的位置,而不是一个换行符(读取到的数据不包括delimiter)
-n num读取num个字符,而不是整行字符。例如:read -n 1
-p prompt显示提示信息,提示内容为prompt。
-r原样读取,不把反斜杠字符解释为转义字符。
-s静默模式,不会在屏幕上显示输入的字符。当输入密码和其他确认信息时,这是很有必要的。
-t seconds设置超时时间,单位为秒。如果用户没有在指定时间内输入完成,那么 read 将会返回一个 非0 的退出状态,表示读取失败。例如:read -t 10
-u fd使用文件描述符 fd 作为输入源,而不是标准输入,类似于重定向。

需求:

使用 read 命令给多个变量赋值

vim小技巧:按pp可以往下复制,u为撤销功能,ctrl+r为恢复功能
vim demo6.sh

#内容
#!/bin/bash
# 使用read命令读取数据,要有提示信息 "请输入姓名, 年龄, 爱好" 将数据赋值给多个变量
read -p "请输入姓名. 年龄, 爱好: " name age hobby
# 打印每一个变量的值
echo "姓名: ${name}"
echo "年龄: ${age}"
echo "爱好: ${hobby}"
#结束
[root@localhost ~]# sh demo6.sh
请输入姓名. 年龄, 爱好: 乐心湖 18 国漫
姓名: 乐心湖
年龄: 18
爱好: 国漫

读取一个字符

vim demo6.sh
#内容
#!/bin/bash
# 使用read命令读取数据,要有提示信息"您确定要删除数据吗(请输入y/n)" 并且设置读取一个字符
read -p "您确定要删除数据吗(请输入y/n): " -n 1 char
# 打印这个字符输出
printf "\n"
echo "您输入的字符: ${char}"
#结束

[root@localhost ~]# sh demo7.sh
您确定要删除数据吗(请输入y/n): y
您输入的字符: y

限制时间输入

在终端控制台输入时,设置指定时间内输入密码

#!/bin/bash
# 使用read命令读取数据,要有提示信息 “请输入密码(10秒内)” 并且设置限制时间为10秒
read -t 10 -sp "请输入密码(10秒内): " pwd1
printf "\n"
read -t 10 -sp "请再次输入密码(10秒内): " pwd2
printf "\n"
if [ $pwd1 == $pwd2 ]
then
        echo "密码一致,校验通过"
else
        echo "密码不一致,校验失败"
fi

exit退出

exit 用于退出当前Shell环境进程结束运行,并且可以发挥一个状态码,一般使用 $? 可以获取退出状态码。

exit #默认返回状态码0,代表命令执行成功

declare设置变量

declare命令用于声明shell变量。可用来声明变量并设置变量的属性,也可用来显示shell函数。若不加上任何参数,则会显示全部的shell变量与函数(与执行set指令的效果相同)。

主要应用于:

declare设置变量的属性[重要]

查看全部Shell变量与函数

declare 查看全部Shell变量

declare -f 查询所有函数的定义

declare -F 查询所域函数的名称列表

实现关联数组变量

declare设置变量的属性语法

declare [+/-][aArxif][变量名称=设置值]

+/-[变量名称=设置值]+/-""可用来指定变量的属性,"+"则是取消变量所设的属性。
a array设置为普通索引数组
A Array设置为key-vajue关联数组
r readonly将变量设置为只读,也可以使用 readonly
x exprot设置变量成为环境变量,也可以使用 export
int设置为整型变量
f function设置为一个函数变量
[root@localhost ~]# declare -i age=18 
[root@localhost ~]# echo ${age}
18         #此时age只能是整形
[root@localhost ~]# age=abc 
[root@localhost ~]# echo ${age}
0         #发现abc修改无效,直接为0了
[root@localhost ~]# age=17 
[root@localhost ~]# echo ${age}
17        #发现17修改有效
[root@localhost ~]# declare +i age
[root@localhost ~]# age=abc
[root@localhost ~]# echo ${age}
abc     #取消i后修改有效了    
[root@localhost ~]# declare -r age
        #添加只读属性
[root@localhost ~]# echo ${age}
abc
[root@localhost ~]# age=17
-bash: age: 只读变量     #修改失败

实现key-value关联数组变量语法

关联数组也称为 "键值对(key-value)"数组, 键(key)也即字符串形式的数组下标,值(value)也即元素值。

这就好比python中的字典,java中的map

declare -A 关联数组变量名=([key1]=值1 [key2]=值2 ...)

declare 也可以用于定义普通索引数组

  • -a:参数创建普通或索引数组
  • -A:创建关联数组
declare -a 关联数组变量名=(值1 值2 ...)
declare -a 关联数组变量名=([O]=值1 [1]=值2 ...)

获取指定key的值

${关联数组变量名[key]}

获取所有值

${关联数组变量名[*]}

${关联数组变量名[@]}

[root@localhost ~]# vim demo10.sh

#内容
#!/bin/bash
#创建索引数组
echo "创建索引数组"
declare -a array1=(100 abc "乐心湖")
#获取索引数组数据
echo "打印array1数组的所有元素: ${array1[*]}"
echo "打印array1数组第三个元素:  ${array1[2]}"
printf "\n"
#创建关联数组
echo "创建关联数组"
declare -A array2=(["name"]="乐心湖" ["age"]=18 ["域名"]="xn2001.com")
#获取索引数组数据
echo "获取array2数组的所有元素: ${array2[*]}"
echo "获取array2数组key为age的元素: ${array2[age]}"
#结束

[root@localhost ~]# sh demo10.sh
创建索引数组
打印array1数组的所有元素: 100 abc 乐心湖
打印array1数组第三个元素:  乐心湖

创建关联数组
获取array2数组的所有元素: 乐心湖 xn2001.com 18
获取array2数组key为age的元素: 18
vim小技巧,剪切当前行使用dd,然后用p粘贴。

Shell算术运算符

expr

expr是evaluate expressions的缩写,译为"求值表达式"。Shell expr 是一个功能强大,并且比较复杂的命令,
它除了可以实现整数计算,还可以结合一些选项对字符串进行处理,例如计算字符串长度、字符串比较、字符串匹
配、字符串提取等,后续讲解。

语法:

expr 算术运算符表达式 例如:expr 1 + 9 这里的空格是必须的。

赋值给变量

result=`expr 算术运算符表达式`

注意:这里是 ``

=两边不能有空格

演示:

[root@localhost ~]# expr 1 + 5
6
[root@localhost ~]# result=`expr 1 + 9` 
[root@localhost ~]# echo ${result}
10

下表列出了常用的算术运算符,假定变量a为1,变量b为2

运算符说明举例
+加法expr $a + $b 结果为 3
-减法expr $a - $b 结果为 -1
*乘法expr $a \* $b 结果为 2
/除法expr $b / $a 结果为 2
%求余expr $b % $a 结果为 0
=赋值a=$b 把变量b的值赋给a
四则运算中如果使用了(),也需要转义 \( 1 + 1 \)

运算符演示

vim demo13.sh
#内容
#!/bin/bash
#使用read命令读取输入2个数字
read -p"请输入第一个数字:" a
read -p"请输入第二个数字:" b
#对2个数字进行算术运算
echo "a=${ia} , b=${b}"
echo "a+b=`expr $a + $b`"
echo "a-b=`expr $a - $b`"
echo "a*b=`expr $a \* $b`"
echo "b/a=`expr $b / $a`"
echo "b%a=`expr $b % $a`"
#结束
[root@localhost ~]# sh demo13.sh
请输入第一个数字:9
请输入第二个数字:3
a= , b=3
a+b=12
a-b=6
a*b=27
b/a=0
b%a=3

Shell比较运算符

整数比较运算符

语法

下表列出了常用的比较运算符,假定变量 a 为 1,变量 b 为 2:

运算符说明举例
-eqequals 检测两个数是否相等,相等返回 0, 否则返回1。[ $a -eq $b ] 返回 1。
-nenot equals检测两个数是否不相等,不相等返回 true。[ $a -ne $b ] 返回 0。
-gtgreater than检测左边的数是否大于右边的,是返回0, 否则1[ $a -gt $b ] 返回 1。
-ltlower than检测左边的数是否小于右边的,是返回0, 否则1[ $a -lt $b ] 返回 0。
-gegreater equals检测左边的数是否大于等于右边的[ $a -ge $b ] 返回 1。
-lelower equals检测左边的数是否小于等于右边的,是返回0, 否则1[ $a -le $b ] 返回 0。
<检测左边的数是否小于右边的,是返回0, 否则1(($a<$b)) 返回0
<=检测左边的数是否小于等于右边的,是返回0, 否则1(($a<=$b)) 返回0
>检测左边的数是否大于右边的,是返回0, 否则1(($a>$b)) 返回1
>=检测左边的数是否大于等于右边的,是返回0, 否则1(($a>=$b)) 返回1
==检测左边的数是否等于右边的,是返回0, 否则1(($a==$b)) 返回1
!=检测左边的数是否不等于右边的,是返回0, 否则1(($a!=$b)) 返回0

注意:

整数比较运算符只支持整数,不支持小数与字符串(字符串比较后续讲解),除非字符串的值是整数数字。

每个命令都有返回值, 这个后面我们会讲解退出状态再具体说明, 返回0代表成功, 返回1代表失败

演示

operation2.sh 脚本代码

#!/bin/bash
a=1 b=2
echo "a=${a} b=${b}"
if [ $a -eq $b ]
then
   echo "$a -eq $b : a 等于 b"
else
   echo "$a -eq $b: a 不等于 b"  # 输出这个
fi
if [ $a -ne $b ]
then
   echo "$a -ne $b: a 不等于 b"  # 输出这个
else
   echo "$a -ne $b : a 等于 b"
fi
if [ $a -gt $b ]
then
   echo "$a -gt $b: a 大于 b"
else
   echo "$a -gt $b: a 不大于 b"  # 输出这个
fi
if [ $a -lt $b ]
then
   echo "$a -lt $b: a 小于 b"   # 输出这个
else
   echo "$a -lt $b: a 不小于 b"
fi
if [ $a -ge $b ]
then
   echo "$a -ge $b: a 大于或等于 b"
else
   echo "$a -ge $b: a 小于 b"  # 输出这个
fi
if [ $a -le $b ]
then
   echo "$a -le $b: a 小于或等于 b"  # 输出这个
else
   echo "$a -le $b: a 大于 b"
fi

if (($a > $b))
then
   echo "$a > $b: a 大于 b"
else
   echo "$a > $b: a 不大于 b"
fi
if (($a < $b))
then
   echo "$a < $b: a 小于 b"
else
   echo "$a < $b: a 不小于 b"
fi
if (($a >= $b))
then
   echo "$a >= $b: a 大于或等于 b"
else
   echo "$a >= $b: a 小于 b"
fi
if (($a <= $b))
then
   echo "$a <= $b: a 小于或等于 b"
else
   echo "$a <= $b: a 大于 b"
fi

运行效果

字符串比较运算符

可以比较2个变量, 变量的类型可以为数字(整数,小数)与字符串

语法

下表列出了常用的字符串运算符,假定变量 a 为 "abc",变量 b 为 "efg":

字符串比较可以使用 [[]][] 2种方式

运算符说明举例
== 或 =相等。用于比较两个字符串或数字,相同则返回 0。可以使用=[ $a == $b ] 返回1
[ $a = $b ] 返回 1
[[ $a == $b ]] 返回1
[[ $a = $b ]] 返回1
!=不相等。用于比较两个字符串或数字,不相同则返回 0。[ $a != $b ] 返回 0
[[ $a != $b ]] 返回 0
<小于, 用于比较两个字符串或数字, 小于返回0, 否则返回1[ $a \< $b ] 返回 0<br/>[[ $a < $b ]] 返回 0
>大于, 用于比较两个字符串或数字, 大于返回0, 否则返回1[ $a \> $b ] 返回 1<br/>[[ $a > $b ]] 返回 1
-z检测字符串长度是否为0,如果长度为0,则返回0, 否则返回1。[ -z $a ] 返回 false。
-n检测字符串长度是否不为 0,如果长度不为0,则返回0, 否则返回1。[ -n "$a" ] 返回 true。
$检测字符串是否不为空,不为空返回0, 为空返回1。[ $a ] 返回 true。
字符串比较没有 <= 可以通过 [[ "a" < "b" && "a" == "b" ]]

演示

operation6.sh脚本代码

#!/bin/bash

a="itheima" b="itcast" c=1 d=2
echo "a=${a},b=${b},c=${c},d=${d}"

if [ $a = $b ]
then
   echo "$a = $b : a 等于 b"
else
   echo "$a = $b: a 不等于 b"
fi

if [ $a != $b ]
then
   echo "$a != $b : a 不等于 b"
else
   echo "$a != $b: a 等于 b"
fi

if [[ $a > $b ]]
then
   echo "$a > $b : a 大于 b"
else
   echo "$a > $b: a 不大于 b"
fi

if [ $a \> $b ]
then
   echo "$a > $b : a 大于 b"
else
   echo "$a > $b: a 不大于 b"
fi

if [[ $c > $d ]]
then
   echo "$c > $d : c 大于 d"
else
   echo "$c > $d: c 不大于 d"
fi

if [ -z $a ]
then
   echo "-z $a : 字符串长度为 0"
else
   echo "-z $a : 字符串长度不为 0"
fi

if [ -n "$a" ]
then
   echo "-n $a : 字符串长度不为 0"
else
   echo "-n $a : 字符串长度为 0"
fi

if [ $a ]
then
   echo "$a : 字符串不为空"
else
   echo "$a : 字符串为空"
fi

运行效果

[[]][] 的区别

在说区别之前,我想说的是:推荐使用 [[ 表达式 ]] 即可以实现数字和字符串比较, 并且不需要转义, 不会word splitting

区别1:word splitting的发生

word splitting:会将含有空格字符串进行分拆分割后比较

[[]] 不会有word splitting发生

[] 会有word splitting发生

通过 $? 获取上一个命令的退出状态, 0代表成功, 1代表失败

区别2:转义字符

[[]]< 不需要转义, 格式为 [[ 字符串1 < 字符串2 ]]

[] 需要对 < > 转义 , 格式为 [ 字符串1 \< 字符串2 ]

演示:

[] 执行效果

[[]] 执行效果, 不需要转义执行结果正确

推荐使用 [[ 表达式 ]] 即可以实现数字和字符串比较, 并且不需要转义, 不会word splitting

Shell布尔运算符

介绍

运算符说明举例
!非运算,取反, 表达式为 true 则返回 false,
否则返回 true。
[ ! 表达式 ] 取反。
-oor 或运算,有一个表达式为 true 则返回 true。[ 表达式1 -o 表达式2 ]
-aand 与运算,两个表达式都为 true 才返回 true。[ 表达式1 -a 表达式2 ]

注意布尔运算符放在[] 或 与 test命令 配合使用才有效

布尔运算符常与test命令配合使用, 后续讲解

演示

operation4.sh脚本代码脚本代码

#!/bin/bash
a=1 b=2

if [ $a -lt 2 -a $b -gt 10 ]
then
   echo "$a 小于 2 且 $b 大于 10 : 返回 true"   
else
   echo "$a 小于 2 且 $b 大于 10 : 返回 false"  # $b -gt 10不成立, 输出这个表达式
fi

if [ $a -lt 10 -o $b -gt 10 ]
then
   echo "$a 小于 10 或 $b 大于 10 : 返回 true"  # $a -lt 10 成立, 输出这个表达式
else
   echo "$a 小于 10 或 $b 大于 10 : 返回 false"
fi

if [ ! $a -gt $b ]
then
   echo "$a 大于 $b 取反 : 返回 true"
else
   echo "$a 大于 $b 取反 : 返回 false"   # $a -gt $b 为true , 取反为false, 输出这个表达式
fi

Shell逻辑运算符

介绍

&& 逻辑的 AND [[ 表达式1 && 表达式2 ]]

|| 逻辑的 OR [[ 表达式1 || 表达式2 ]]

! 逻辑非 [[ ! 表达式 ]]

注意

使用 &&|| 的运算符必须放在 [[]](()) 中才有效, 否则报错

! 可以用在 [],[[]] 中, 不可以在(())

演示

operation5.sh脚本代码

#!/bin/bash

a=1 b=2

if [[ $a -lt 10 && $b -gt 10 ]]
then
   echo "返回 true" 
else
   echo "返回 false"  # $b -gt 10 不成立, 输出false
fi

if [[ $a -lt 10 || $b -gt 10 ]]
then
   echo "返回 true"   # $a -lt 10 成立,  输出true
else
   echo "返回 false"  
fi

运行效果

image-20200701172201560

Shell文件测试运算符

使用常用文件测试运算符检查文件

例如: 文件是否存在\是否可读\是否可执行\是否为空\是否可写\是否是目录\是否是普通文件

Linux系统文件类型介绍

-:普通文件

d:目录文件

l:链接文件

b:块设备文件

c:字符设备文件

块设备文件: 比如计算机硬盘/dev/sda

字符设备文件: 比如计算机的USB文件/dev/usb

设备文件都是对应计算机硬件的, 不同的设备文件代表不同的传输数据方式

p:管道文件

介绍

文件测试运算符用于检测文件的各种属性。

属性检测描述如下:

操作符说明举例
-b file检测文件是否是块设备文件,如果是,则返回 true。[ -b $file ] 返回 false。
-c file检测文件是否是字符设备文件,如果是,则返回 true。[ -c $file ] 返回 false。
-d filedirectory, 检测文件是否是目录,如果是,则返回 true。[ -d $file ] 返回 false。
-f filefile, 检测文件是否是普通文件(既不是目录,也不是设备文件)
,如果是,则返回 true。
[ -f $file ] 返回 true。
-g file检测文件是否设置了 SGID 位,如果是,则返回 true。[ -g $file ] 返回 false。
-k file检测文件是否设置了粘着位(Sticky Bit),如果是,
则返回 true。
[ -k $file ] 返回 false。
-p file检测文件是否是有名管道文件,如果是,则返回 true。[ -p $file ] 返回 false。
-u file检测文件是否设置了 SUID 位,如果是,则返回 true。[ -u $file ] 返回 false。
-r fileread,检测文件是否可读,如果是,则返回 true。[ -r $file ] 返回 true。
-w filewrite,检测文件是否可写,如果是,则返回 true。[ -w $file ] 返回 true。
-x fileexecute, 检测文件是否可执行,如果是,则返回 true。[ -x $file ] 返回 true。
-s filesize, 检测文件是否为空(文件大小是否大于0)
,不为空返回 true。
[ -s $file ] 返回 true。
-e fileexists, 检测文件(包括目录)是否存在,如果是,
则返回 true。
[ -e $file ] 返回 true。
file1 -nt file2new than(nt), file1是否比file2新[ file1 -nt file2 ]
file1 -ot file2old than(ot), file1是否比file2旧[ file1 -ot file2 ]

其他检查符:

  • -S: 判断某文件是否 socket。
  • -L: link, 检测文件是否存在并且是一个符号链接。

语法

[ options 文件路径字符串]
或
[[ options 文件路径字符串 ]]

演示

operation6.sh脚本代码

#!/bin/bash
file="/root/operation1.sh"
if [ -w $file ]
then
   echo "文件可写"
else
   echo "文件不可写"
fi
if [ -r $file ]
then
   echo "文件可读"
else
   echo "文件不可读"
fi
if [ -x $file ]
then
   echo "文件可执行"
else
   echo "文件不可执行"
fi
if [ -f $file ]
then
   echo "文件是普通文件"
else
   echo "文件是特殊文件"
fi
if [ -s $file ]
then
   echo "文件不是空"
else
   echo "文件是空"
fi
if [ -e $file ]
then
   echo "文件存在"
else
   echo "文件不存在"
fi
if [ -d $file ]
then
   echo "文件是目录"
else
   echo "文件不是目录"
fi

file2="/root/operation2.sh"
if [ file -nt file2 ]
then
   echo "operation1.sh文件比operation2.sh文件新"
else
   echo "operation1.sh文件不比operation2.sh文件新"
fi

运行效果

operation1.sh文件不可执行, 因为没有可执行权限

查看operation1.sh文件权限

给operation1.sh添加执行权限

重新执行operation6.sh


Last modification:September 30, 2020
如果觉得我的文章对你有用,请随意赞赏