Shell基础入门
linux系统是如何操作计算机硬件CPU,内存,磁盘,显示器等?使用linux的内核操作计算机的硬件Shell介绍...
Shell计算命令
Shell计算命令:expr命令详解介绍expr (evaluate expressions 的缩写),译为“表达...
Shell流程控制
流程控制:if else语句if语法多行写法语法if 条件 then 命令 fi可以将if语句放入一行语...
Shell函数定义
Shell函数:系统函数函数介绍Shell编程和其他编程语言一样, 有函数, 函数是由若干条shell命令组成的...
Shell实用工具
Shell好用的工具: cut使用cut可以切割提取指定列字符字节的数据介绍cut 译为“剪切, 切割”,是一个...
Shell常见的面试题
面试题:查空行问题:使用Linux命令查询 file1.txt 中空行所在的行号file1.txt数据准备xn20...
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解析器
代码语言:javascript复制cat /etc/shells
效果:
解析器类型:
解析器类型 | 介绍 |
---|---|
/bin/sh | Bourne 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/dash | dash(Debian Almquist Shell),也是一种 Unix shell。它比 Bash 小,只需要较少的磁盘空间,但是它的对话性功能也较少,交互性较差。 |
/bin/csh | C Shell是C语言风格Shell |
/bin/tcsh | 是C Shell的一个扩展版本。 |
Centos默认的解析器是bash
代码语言:javascript复制echo $SHELL
含义: 打印输出当前系统环境使用的Shell解析器类型 echo 用于打印输出数据到终端
$SHELL
是全局共享的读取解析器类型环境变量, 全局环境变量时所有的Shell程序都可以读取的变量,
效果
Shell脚本编写规范
shell脚本文件是一个文本文件,后缀名建议使用 .sh
结尾
首行规范
首行需要设置Shell解析器的类型,语法为 #!/bin/bash
主要是设置当前的Shell脚本文件采用bash解析器来运行脚本代码
注释格式
单行注释: #注释内容
多行注释:
代码语言:javascript复制:<<!
# 注释内容
# 注释内容
!
helloworld
代码语言:javascript复制touch helloworld.sh
vim helloworld.sh
#写入shell脚本内容
#!/bin/bash
echo "hello world"
#保存退出
#按esc,输入:wq
#查看内容写入成功否
cat helloworld.sh
脚本文件执行
常用的三种执行方式
- sh解析器执行方式
- bash解析器执行方式
- 仅路径执行方式
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
编辑命令
- 创建 one.txt
- 输出数据 "Hello Shell" 到 one.txt 文件中
输出数据到文件的命令:
数据 >> 文件
这是Linux中重定向内容的知识
执行脚本文件
实现案例
代码语言:javascript复制mkdir /root/xn2001
cd /xn201
touch batch.sh
vim batch.sh
代码语言:javascript复制#!/bin/bash
touch one.txt
echo "Hello Shell" >> one.txt
代码语言:javascript复制ll
sh batch.sh
cat batch.sh
cat one.txt
可以看到 one.txt 文件内就有了 Hello Shell
Shell环境变量
变量用于存储管理临时的数据,这些数据都是在运行内存中的。 变量类型:
- 系统环境变量
- 自定义变量
- 特殊符号变量
系统环境变量
系统提供的共享变量,是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 |
环境变量输出
代码语言:javascript复制echo $PSTH
echo $PWD
echo $LANG
Shell自定义变量
就是自己定义的变量 分类:
- 自定义局部变量
- 自定义常量
- 自定义全局变量
自定义局部变量
就是定义在一个脚本文件中的变量,只能在这个脚本文件中使用的变量。
定义语法: var_name=value
定义规则:
- 变量名称可以有字母,数字和下划线组成,但不能以数字开头。
- 等号两侧不能有空格。
- 在bash环境中,变量的默认类型都是字符串,无法直接进行数值运算。
- 变量的值如果有空格,必须使用双引号括起来。
- 不能使用Shell的关键字作为变量名称。
查询变量值语法:
- 直接使用变量名查询,
$变量名
- 使用花括号查询,
${变量名}
推荐大家使用花括号才是编程的好习惯。
演示:
代码语言:javascript复制[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
演示:
代码语言:javascript复制[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中是否可用。
实现步骤
- 创建2个脚本文件 demo2.sh 和demo3.sh
- 编辑 demo2.sh -> 定义 VAR,执行 demo3.sh
- 编辑 demo3.sh -> 输出全局变量 VAR
- 执行 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,并在脚本文件内部打印脚本文件名字、第一个输入参数、第二个输入参数
代码语言:javascript复制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 中输出输入参数的个数
代码语言:javascript复制vim demo4.sh
#添加内容
echo "输入参数的个数为:"$#
#结束
[root@localhost ~]# sh demo4.sh xn2001 18
demo4.sh
xn2001
18
输入参数的个数为:2
$*、$@
都是获取所有的输入参数,用于以后输出所有参数
区别
不使用双引号括起来,没有区别。 -> 返回格式为:
使用双引号括起来,返回格式有所区别。
- "2 ... n"
- "2" "
使用循环打印所有输入参数可以看出区别
循环语法:
代码语言:javascript复制for var in 列表变量
do #循环开始
命令 #循环体
done #循环结束
案例需求:
在 demo4.sh 中循环打印输出所有输入参数,体验 * 和 @ 的区别
代码语言:javascript复制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代表执行失败。
演示:
执行一个成功命令
代码语言:javascript复制[root@localhost ~]# echo "hello"
hello
[root@localhost ~]# echo $?
0
执行一个失败命令
代码语言:javascript复制[root@localhost ~]# ee
-bash: ee: 未找到命令
[root@localhost ~]# echo $?
127
$$
用于获取当前Shell环境的进程ID号
查看当前Shell环境进程编号
代码语言:javascript复制ps -aux|grep bash
代码语言:javascript复制[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
代码语言:javascript复制小技巧,在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字符串变量
字符串三种格式
单引号方式
双引号方式(推荐)
不使用引号方式
三种格式区别
使用单引号 ''
的字符串:
任何字符都会原样输出,在拼接字符串中使用变量是无效的。
代码语言:javascript复制[root@localhost ~]# var1=666
[root@localhost ~]# echo 'abc${var1}'
abc${var1}
[root@localhost ~]# echo 'abc'${var1}
abc666
[root@localhost ~]#
使用双引号 ""
的字符串:
其中包含了变量,那么该变量会解析得到值,而不是原样输出。
字符串中还可以出现双引号的字字符串,但是需要转义。
代码语言:javascript复制[root@localhost ~]# var2=乐心湖你好
[root@localhost ~]# echo "2020年${var2}"
2020年乐心湖你好
[root@localhost ~]# echo "2020年"${var2}""
2020年"乐心湖你好"
不被引号包围的字符串
不被引号包围的字符串中出现变量时也会被解析,这一点和双引号 ""
一样。
但是变量后面中不能再出现空格,否则无法解析,会被当做其他指令进行。
代码语言:javascript复制[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 左边的所有字符。 |
案例需求演示:
代码语言:javascript复制[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,可以自定义下标
代码语言:javascript复制[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[*]} ...)
演示:
代码语言:javascript复制[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设置别名
代码语言:javascript复制用于给命令设置别名 好处:可以将经常操作比较复杂的命令进行设置别名,通过别名的操作提高工作效率。 若该命令且不带任何参数,则显示所有当前 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 ...]
代码语言:javascript复制
options
表示选项,如下表所示:var
用来存储数据的变量,可以有一个也可以多个。options
和var
都是可选的,如果没有提供变量名,那么读取的数据将存放到环境变量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 命令给多个变量赋值
代码语言:javascript复制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
爱好: 国漫
读取一个字符
代码语言:javascript复制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
限制时间输入
代码语言:javascript复制在终端控制台输入时,设置指定时间内输入密码
#!/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关联数组变量语法
代码语言:javascript复制关联数组也称为 "键值对(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
这里的空格是必须的。
赋值给变量
代码语言:javascript复制result=`expr 算术运算符表达式`
注意:这里是 =两边不能有空格
演示:
代码语言:javascript复制[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 )
运算符演示
代码语言:javascript复制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:
运算符 | 说明 | 举例 |
---|---|---|
-eq | equals 检测两个数是否相等,相等返回 0, 否则返回1。 | $a -eq $b 返回 1。 |
-ne | not equals检测两个数是否不相等,不相等返回 true。 | $a -ne $b 返回 0。 |
-gt | greater than检测左边的数是否大于右边的,是返回0, 否则1 | $a -gt $b 返回 1。 |
-lt | lower than检测左边的数是否小于右边的,是返回0, 否则1 | $a -lt $b 返回 0。 |
-ge | greater equals检测左边的数是否大于等于右边的 | $a -ge $b 返回 1。 |
-le | lower 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 脚本代码
代码语言:javascript复制#!/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 [ $a < $b ] 返回 0 |
大于, 用于比较两个字符串或数字, 大于返回0, 否则返回1 | $a > $b 返回 1 [ $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脚本代码
代码语言:javascript复制#!/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。 | ! 表达式 取反。 |
-o | or 或运算,有一个表达式为 true 则返回 true。 | 表达式1 -o 表达式2 |
-a | and 与运算,两个表达式都为 true 才返回 true。 | 表达式1 -a 表达式2 |
注意布尔运算符放在
[]
或 与 test命令 配合使用才有效undefined布尔运算符常与test命令配合使用, 后续讲解
演示
operation4.sh脚本代码脚本代码
代码语言:javascript复制#!/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脚本代码
代码语言:javascript复制#!/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
运行效果
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 file | directory, 检测文件是否是目录,如果是,则返回 true。 | -d $file 返回 false。 |
-f file | file, 检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 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 file | read,检测文件是否可读,如果是,则返回 true。 | -r $file 返回 true。 |
-w file | write,检测文件是否可写,如果是,则返回 true。 | -w $file 返回 true。 |
-x file | execute, 检测文件是否可执行,如果是,则返回 true。 | -x $file 返回 true。 |
-s file | size, 检测文件是否为空(文件大小是否大于0),不为空返回 true。 | -s $file 返回 true。 |
-e file | exists, 检测文件(包括目录)是否存在,如果是,则返回 true。 | -e $file 返回 true。 |
file1 -nt file2 | new than(nt), file1是否比file2新 | file1 -nt file2 |
file1 -ot file2 | old than(ot), file1是否比file2旧 | file1 -ot file2 |
其他检查符:
- -S: 判断某文件是否 socket。
- -L: link, 检测文件是否存在并且是一个符号链接。
语法
代码语言:javascript复制[ options 文件路径字符串]
或
[[ options 文件路径字符串 ]]
演示
operation6.sh脚本代码
代码语言:javascript复制#!/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
版权属于:乐心湖's Blog
本文链接:https://cloud.tencent.com/developer/article/1774942
声明:博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!