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;
<font color=red>/bin/bash</font><font color=red>Bourne Again Shell它是Bourne Shell的扩展,简称bash,是LinuxOS默认shell,有灵活和强大的编辑接口,同时又很友好的用户界面,交互性很强;</font>
/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 30th, 2020 at 02:01 am
如果觉得我的文章对你有用,请随意赞赏