linux基础之bash特性
1、命令历史
命令历史包含的环境变量
$HISTSIZE:命令历史记录的条数
$HISTFILE:命令历史文件~/.bash_history
$HISTFILESIZE:命令历史文件记录历史命令的条数
$HISTCONTROL:控制命令历史的记录方式
关于这个$HISTCONTROL环境变量值的介绍:
ignoredups:设置为这个值时,忽略重复的命令记录到命令历史中,这重复的命令必须是连续的,也就是挨着的($HISTCONTROL默认是ignoredups这个值)
如何设置:
export HISTCONTROL=”ignoredups”
ignorespace:设置为这个值时,忽略所有以空白字符开头的命令记录到命令历史中
如何设置:
export HISTCONTROL=”ignorespace”
ignoreboth:设置为这个值时,上面两个之所对应的功能都生效
如何设置:
export HISTCONTROL=”ignoreboth”
命令历史的使用
history -d num :清除命令历史记录中指定的命令历史编码数
history -c:清除所有命令历史记录
histroy num:显示历史命令记录中最近num条记录
history -a:手动追加当前会话命令历史缓冲区的命令到命令历史文件
命令历史的快捷键
!!:调用上一次使用的命令
!+num:调用历史命令记录中编号为num的命令
!+string:调用命令历史记录中最近一次使用的以string为开头的命令
!+$:调用上一条命令的最后一个参数的快捷键
ESC+ . :调用上一条命令的最后一个参数的快捷键,按键盘上ESC键,松开后再按点号
ALT+ . :调用上一条命令的最后一个参数的快捷键,按键盘上ALT键,不松开接着按点号(可能有些不管用)
2、命令补全
命令补全使用方式:当我敲击一个命令时,可以写前几个字符,然后使用tab键补全
命令补全的实现机制:bash根据PATH环境变量定义的路径,自左向右的在每个路径下搜索以给定字符为开头的对应的命名二进制可执行文件,如果找寻了所有路径只包含一个,那么直接补全,如果包含多个,那么在使用一次tab键,打印给定字符包含的所有可执行命令
bash执行命令过程
外部命令:bash根据PATH环境变量定义的路径,自左向右的在每个路径下搜索以给定命令命名二进制可执行文件,第一次找到即为要执行的命令
3、路径补全
路径补全的实现机制:把用户给出的字符串当做路径的开头,并在其指定上级目录下搜索以指定的字符串开头的文件名,如果唯一则按tab键补全路径,如果不唯一则需要再按一下tab键,此时会列出以这个字符串开头的所对应的文件列表。
注意:他还有一个特殊的机制,那就是当我们给定的字符串搜索时,如果这个目录下的所有文件包含这个字符串,同时还包含了其他相同字符,那么再按一下tab键会补全到所有相同字符串的位置
4、命令行展开
~:展开为用户的家目录
使用案例
[root@oldboy ~]# cd ~oldboy [root@oldboy oldboy]# pwd /home/oldboy
{}:可承载一个以逗号分割的列表,并将其展开为多个路径
使用方式
/tmp/{a,b} 展开为 /tmp/a /tmp/b
/tmp/{tom,jerry}/ha 展开为 /tmp/tom/ha /tmp/jerry/ha
5、命令执行结果状态
命令执行后的结果无非两种,成功或者失败,bash使用特殊变量$?保存最近一条命令执行的状态结果
状态码
0:表示成功
1-255:表示失败
程序的执行有两类结果
一类是:程序的返回值
另一类是:程序的执行状态结果
6、命令别名-alias
基本介绍
命令取的另外一个名字,我们可以把很长的命令格式,通过一个别名,把它简化为一个简短的名字。
基本用法
alias [-p] [name[=value] ... ]
常用参数
-p:打印所有定义的别名
使用注意
alias命令是一个内建命令,如果alias不带任何参数或者选项表示列出所有的别名,如果要定义别名使用alias 命令简写=”命令长格式”
在命令行定义的别名仅对当前shell进程有效。如果想永久有效,需要定义在配置文件中
配置文件有两种:
仅对当前用户有效
~/.bashrc
对所有用户有效
/etc/bashrc
任何修改配置文件,只能被新进程或者让新进程重新读取才生效(这里的进程指的是bash进程)
让bash进程重新读取使用source命令
source 配置文件
. 配置文件
注:新配置的配置文件不会立刻生效,需让bash进程重新读取才会生效
撤销别名:unalias
unalias 别名 :撤销指定别名
unalias -a:撤效全部定义的别名
注意:如果不想使用别名,但是又不想去除别名定义,那么可以在使用别名前加一个反斜线[ ],或者补全命令的全路径
7、Glob
基本介绍
bash中用于实现文件名通配
基本使用
通配符
*
基本介绍
匹配任意长度的任意字符
基本使用
a*c 表示 a111c,asdc,ac等,但是不表示acb
?
基本介绍
匹配任意单个字符,必须包含单个字符
基本使用
a?b 表示 acb,adb等,但是不表示adbc,acnb,ab
[]
基本介绍
匹配指定范围内的任意单个字符,如果范围内是小写字母,那么是不区分大小写的,如果范围内是大写,那么只是取大写范围。
注意:如果要匹配连字符[ - ],那么要使用转义符号
案例演示
a[-cv]b 表示匹配 a-b,acb,avb等
基本使用
[abc] 表示 a,b,c等,但不表示ab,ac,abc等
a[a-z]c 表示 aCc,acc,aDc,adc等
[^]
基本介绍
匹配指定范围之外的任意字符
基本使用
a[^0-9] 表示 ab,a^,a@等,不表示a1,a2等
专用字符集合表示法
[:digit:]:任意数字相当于0-9,这里只表示数字,不是匹配数字,匹配数字要写成[[:digit:]]
[:lower:]:任意的小写字母,这里只表示小写字母,不是匹配小写字母,匹配小写字母要写成[[:lower:]]
[:upper:]:任意的大写字母,这里只表示大写字母,不是匹配大写字母,匹配大写字母要写成[[:upper:]]
[:alpha:]:任意的大小写字母,这里只表示大小写字母,不是匹配大小写字母,匹配大小写字母要写成[[:alpha:]]
[:alnum:]:任意的数字和字母,这里只表示数字和大小写字母,不是匹配数字和大小写字母,匹配数字和大小写字母要写成[[:alnum:]]
[:space:]:任意的空格,这里只表示空格,不是匹配空格,匹配空格要写成[[:space:]]
[:punct:]:任意的标点字符,这里只表示标点符号,不是匹配标点符号,匹配空格要写成[[:punct:]]
案例演示
列出/var目录下,非字母开头,后面跟任意单个字母的txt文件
ls -l /var/[^[:alpha:]][[:alpha:]].txt
8、bash的快捷键
ctrl+l:清屏操作,相当于clear命令
ctrl+a:将光标跳转至命令的首部
ctrl+e:将光标跳转至命令的尾部
ctrl+c:取消命令执行
ctrl+u:删除光标所在位置之前的全部字符
ctrl+k:删除光标所在位置之后的全部字符
9、输入、输出重定向及管道
程序是由指令加数据组成,那么程序都有读入数据的需求(Input),程序也有输出数据的需求(Output)
程序读入数据的来源有很多:文件、用户键盘输入等
程序输出数据的地方有很多:保存至文件、输出到屏幕等
那么程序读入数据或者输出数据的选择就有很多,如果程序每一次执行时都需要指定程序读入数据或者输出数据的来源或者去处,这样会很麻烦,因此,就会有缺省或者说默认的值
缺省输入或者默认输入叫做标准输入,默认的或者缺省的输入是键盘输入
比如说cat命令,这里可以说是cat程序,如果你不指定文件,也就是数据来源,那么它默认从键盘获取你的输入。但是有些命令自身具有默认的数据输入位置,比如ls命令,如果不给定ls命令输入的数据,那么默认以当前位置为输入数据
缺省输出或者默认输出叫做标准输出,默认的或者缺省的输出是监视器(monitor)
默认的错误输出或者缺省的错误输出叫做标准错误输出
不管是bash报错还是某个命令自身报错都属于标准错误输出,这个输出是与标准输出不相瓜葛的输出,即是一个独立的输出数据流,但是他的输出位置默认是监视器(monitor)
I/O重定向:改变标准输入或者标准输出的位置
输出重定向( >、>> )
语法
COMMAND > new_pos
COMMAND >> new_pos
分类
>:表示覆盖重定向,目标文件原有内容会被覆盖
案例演示
[root@oldboy ~]# ls /var > /tmp/var.txt
>>:追加重定向,在目标文件原有内容下追加新内容
案例演示
[root@oldboy ~]# ls /etc/ >> /tmp/etc.txt
注意:输出重定向是非常危险的操作,误操作就可能把你的重要数据给覆盖了。
问题:bash中有没有可以设置关闭和打开这个输出重定向功能呢?
解决方式
set -C 命令:禁止将内容覆盖输出到已有文件内容,但是不存在的文件是可以进行输出重定向的,这个对标准错误输出也起作用
另外一个现实:
输出重定向新问题:bash支持强制输出覆盖:>|
案例演示
cat /etc/fstab >| /tmp/a.txt
set +C命令:关闭禁止将内容覆盖输出到已有文件内容,也就是可以覆盖输出到已有内容的文件
标准错误输出
当我们执行一条有时命令会报错,但是这个错误输出默认是输出到监视器,那么我们怎么重定向这个标准的错误输出呢?
标准错误输出重定向
语法
COMMAND 2> new_pos
COMMAND 2>> new_pos
分类
2>:表示覆盖重定向错误输出流,目标文件原有内容会被覆盖
案例演示
[root@oldboy ~]# ls /varr 2> /tmp/var.txt
2>>:表示追加重定向错误输出流,在目标文件原有内容下追加新内容
案例演示
[root@oldboy ~]# ls /etcc/ 2>> /tmp/etc.txt
我们想把错误的输出或者正确的输出到不同位置
语法
COMMAND >> new_pos 2>> err_new_pos
COMMAND > new_pos 2> err_new_pos
错误或者正确的输出流合并至同一个数据流进行重定向
语法
COMMAND &> new_pos
COMMAND &>> new_pos
COMMAND > new_pos 2> &1
&>:覆盖重定向
&>>:追加重定向
2> &1:表示将标准错误的输出流导向与标准输入出流同一个地方,而标准输出流导向了一个文件,那么标准错误输出流也导向与标准输出流同样的地方
输入重定向
输入重定向使用的意义:有些命令在执行时不能够带文件作为参数的命令,默认只能从标准输入中读数据,那么我们可以强行使用输入重定向让他从文件获取数据
语法
COMMAND < old_pos
old_pos为一个文件或者其他数据来源
输入重定向有没有使用两个小于号的必要?其实是有的,(<<)两个小于号是用来创建文档的
案例演示
[root@oldboy ~]# cat <<EOF > 123 > asd > qe > 123 > > EOF 123 asd qe 123
这个有什么用呢?
默认从键盘键入的字符,输出到的是监视器上,那么我们可以将这些输出的字符重定向到我们指定的文件
案例演示
[root@oldboy ~]# cat >> /tmp/b.txt <<EOF > hello world > are you ok? > thanks > byebye > EOF [root@oldboy ~]# cat /tmp/b.txt hello world are you ok? thanks byebye
管道
基本介绍
我们可以将一个命令的输出当做另一个命令的输入,并且这个样无限下去
基本语法
COMMAND1 | COMMAND2 | COMMAND3....
使用案例
[root@oldboy ~]# echo $PATH | tr 'a-z' 'A-Z' /USR/LIB64/QT-3.3/BIN:/USR/LOCAL/SBIN:/USR/LOCAL/BIN:/SBIN:/BIN:/USR/SBIN:/USR/BIN:/ROOT/BIN
10、提供了编程环境
基本介绍
程序是由指令和数据组成,同时也可以说指令是由数据结构与算法组成
程序的编程风格
过程式:一指令为中心,数据服务与指令
过程式编程的执行分类
顺序执行
循环执行
选择执行
对象式:以数据为中心,指令服务于数据
shell程序:提供了编程能力,解释执行
程序的执行方式
计算及只能执行二进制指令
编程语言
低级语言:汇编
高级语言:
高级语言又分为
编译型:高级语言依赖于编译器,最终转换成二进制的目标代码
c,c++,java
解释型:高级语言依赖于解释器,最终生成机器代码(二进制代码)
shell,perl、python
shell编程是过程式的编程、并且是解释执行的
shell既然是一门语言,那么它也具有编程语言的基本结构
数据存储:变量、数组
表达式
语句
函数
shell编程的本质就是命令的堆砌。shell严重依赖当前操作系统的环境
shell脚本本身是一个文本文件,但是这个shell脚本有一定的使用规范,比如,脚本内容第一行必须声明使用的shell程序。这第一段内容表示告诉cpu用哪个shell解释器,并且用这个shell解释去来解释下面内容
#!/bin/bash
#!/bin/csh
执行shell脚本时注意事项
如果我们当前的环境变量中不包含当前脚本要执行的路径时。要执行脚本需要指定脚本的绝对路径或者相对路径
shell脚本如何执行?
首先,如果脚本具有可执行权限,那么当这个脚本执行时,将会读取当前脚本中的第一行,找到对应路径下的解释器,用这个解释器来解释脚本除第一行以下内容
其次,如果脚本不具有可执行权限,那么我们可以手动给shell脚本添加一个解释器,去解释这个shell脚本
解释执行的原理理论:
解释执行语言:其实cpu执行的是解释器,由解释器读取你的源代码,由解释器将源代码解释成二进制代码后交给cpu再执行
11、bash基本特性之变量
基本介绍
如果我们指定了变量类型,那么决定了数据的存储格式,存储空间大小,参与的运算符
变量分类
字符型
数值型
整型
浮点型
编程语言又分为
强类型编程语言
定义变量必须指定变量的类型,参与运算必须符合类型的要求。变量必须事先定义
Go语言,c语言,c++
弱类型编程语言
无需显示指定类型,默认均为字符型。参与运算会自动进行隐式类型转换。变量无需事先被定义可直接调用,不会报错
bash,python、javascript
bash的变量种类
根据变量生效范围等来分类
本地变量:生效范围为当前shell进程,对当前shell之外的其他shell进程,包括当前shell的子shell进程都无效
案例演示
[root@oldboy ~]# b=12 [root@oldboy ~]# echo $b 12 [root@oldboy ~]# pstree //查看当前的进程树 init─┬ ├─sshd───sshd───bash───pstree //这里只有一个shell进程 [root@oldboy ~]# bash //开启一个子shell进程 [root@oldboy ~]# echo $b //在子进程中获取变量b的值为空,表示不存在变变量b [root@oldboy ~]# pstree init─┬ ├─sshd───sshd───bash───bash───pstree //从这里看到我们打开了一个子shell进程
环境变量:生效范围为当前shell进程及其子进程
局部变量:生效范围为当前shell进程中的某代码片段(通常是函数,函数执行完,变量就被销毁)
位置变量:位置变量有$1,$2,......$n。当脚本执行时,在脚本代码中表示命令行向脚本中传递的参数
特殊变量
$?:打印上一个程序执行的结果状态值
$0:打印shell脚本名称
$@:
$#
本地变量
变量赋值:name=value
案例演示
[root@oldboy ~]# a=1
变量引用:${key},但是大部分情况大括号可省略,直接写成$key
变量的值可以是以下内容
①可以直接赋值一个数字或者字符串,如果字符串中有空格需要时用引号引起来,如果没有空隔可以不用加引号,建议加引号
②变量的引用。name=”$name” 值是另一个变量的值
③命令的引用。name=`COMMAND` 值为一个命令,但是这个变量存储的是命令执行后返回的结果
④命令的引用。name=$(OCMMAND) 值为一个命令,但是这个变量存储的是命令执行后的返回结果
案例演示
[root@oldboy ~]# a=1 [root@oldboy ~]# [root@oldboy ~]# echo $a 1 [root@oldboy ~]# echo ${a} 1
使用注意:
有时候我们引用变量时,必须给定大括号,不然会产生歧义。如下案例
[root@oldboy ~]# a="apple" [root@oldboy ~]# echo "this is $apple" this is [root@oldboy ~]# echo "this is ${a}pple" this is applepple
变量引用中的引号
单引号’ ’
单引号为强引用,引号中的内容如果有变量的引用,那么会原值输出,也就是如果为$a,那么输出也是$a。也就是保持原来的字符串不变输出
双引号””
双引号为弱引用,引号中的内容如果有变量引用,那么会将变量转化成值再输出
显示已定义的所有变量(本地变量,环境变量)
set命令
销毁已定义的某个变量
unset key_name
环境变量
变量的声明和赋值
export name=value
declare -x name=value
变量先赋值在导出
name=”asd”
declare -x name
变量的引用
$name
name}
显示所有的环境变量
env命令
export命令
printenv命令
撤销环境变量
unset name
bash有许多内建的环境变量,定义环境变量时,尽量避免与环境变量相同而影响系统正常运行
PATH、SHELL、UID、HISTSIZE、HOME、PWD、OLDPWD、HISTFILE、PS1
位置变量
在脚本代码中调用通过命令行传递给脚本的参数
$1、$2、$3......:对应调用命令行参数1,参数2
$0:执行脚本命令本身
$*:传递给脚本的所有参数
把传递给脚本的变量组合成一个字符串使用
$@:传递给脚本的所有参数
把传递给脚本的变量不进行组合,是多少个就是多少个使用
$#:传递给脚本的参数个数
shell脚本支持shift命令。shell脚本传递的命令行参数默认保存在一个栈中(为了好理解意想的),当我们使用shift命令,那么会从这个栈中弹出相应的参数个数。shift命令语法:shift [n]
注意
当我们要将一个$符号进行输出时,需要进行转义,因为$符号在bash中有特殊含义,表示变量引用
案例
判断给出文件的行数,要求使用一个简单脚本实现
#!/bin/bash lines=$(wc -l $1|cut -d " " -f1) echo "$1 has $lines lines"
变量的命名规则
不能使用程序的保留字,例如:if、for
只能使用数字、字母、下划线命名,但是不能以数字开头
变量名尽量定义形象可观,见名知义
bash中也支持只读变量定义
readonly name=value
declare -r name=value
注意
只读变量不能修改,不能赋值,不能销毁,只能等到shell进程结束才会被销毁。因此,只读变量也叫常量
案例演示
[root@oldboy ~]# declare -r name="xxx" [root@oldboy ~]# name="123" bash: name: readonly variable
12、bash的配置文件
基本介绍
配置文件分类
按生效范围划分,存在两类
全局配置文件
/etc/pfofile
/etc/profile.d/*.sh
/etc/bashrc
~/.bashrc
~/.bash_profile
个人(用户)配置文件
按功能划分,存在两类
profile类配置文件:是为交互式登录的shell提供配置
全局的配置文件:/etc/profile,/etc/profile/profile.d/*.sh
个人的配置文件:~/.bash_profile
profile类配置文件的主要作用:
①用于定义环境变量
②运行命令或者脚本
我们可以在/etc/profile.d/目录下建立一个文件以.sh结尾的文件,当登录到linux时,它会自动去执行这个/etc/profile.d目录下的所有文件。因此,这个功能可以用来我们自定制当用户登录时给出的提示
bash类配置文件:是为非交互式登录的shell提供配置
全局的配置文件:/etc/bashrc
个人的配置文件:~/.bashrc
bashrc类配置文件的主要作用:
①定义命令别名
②定义本地本地变量
但是这类文件没有严格的界限,即有可能非交互式登录可能用到交互式登录的配置文件,交互式登录也可能用到非交互式登录类的配置文件
shell登录分类
交互式登录:直接通过终端输入账号密码的登录。或者使用su - username也称为交互式登录
非交互登录:使用su uername方式登录的,或者图形界面下打开的终端,或者执行脚本(脚本执行起来时,这个脚本会自己打开一个shell进程来单独运行这个脚本)
使用注意
linux中如果某些配置文件过大,会将过大的配置文件分割成多个片段,每个片段用来保存一部分配置。而这些片段会被放置在某个特定的目录下,而这个目录下的所有以.sh结尾的文件都是大配置文件的组成部分。比如/etc/profile文件的片段文件存放在etc/profile.d/目录中,而目录下以.sh结尾的文件都是/etc/profile文件的组成部分。
交互式登录shell读取配置文件的顺序
首先会去读取/etc/profile文件,其次会去读取/etc/profile.d/*.sh文件,然后会去读取用户家目录下的~/.bash_profile文件,再然后去读取家目录下的~/.bashrc,最后读取/etc/bashrc
非交互式登录shell读取配置文件的顺序
首先会去读取用户家目录下的~/.bashrc,其次会去读取/etc/bashrc,最终会去读取/etc/profile.d/*.sh文件
问题
定义对所有用户都生效的别名,定义在那个配置文件?
/etc/bashrc文件
所有用户登录时都会出现一些提示信息,当以在那个文件下?
/etc/profile.d/目录下
让用户(管理员或者普通用户)的PATH环境变量的值多出一个路径,应该定义在那个配置文件。例如:多出一个/tmp/user/bin/
只对管理员生效的话定义在~/.bash_profile
对所有用户生效的话定义在/etc/profile.d/目录下或者直接定义在/etc/profile文件中
使用注意
对配置文件进行配置后,需要重新生效配置文件,生效方式有三种
①重新登录
②使用 . 配置文件,重新加载配置文件
③使用source命令来重新加载配置文件
但是,重新加载新的配置文件后,会出现意想不到的结果,也就是如果你重复加载多次,那么会在环境变量中加多个配置文件的相同路径
13、bash的算数运算
基本介绍
bash中提供了可以进行算数运算的语法
实现算数运算的方式
let 命令实现
基本语法
let var=算数表达式
使用案例
num=1 num2=3 let sum=$num+$num2 echo “$sum”
$[]来实现
基本语法
var=$[算数表达式]或者直接使用$[算数表达式]来进行算数运算
使用案例
a=1 b=2 echo “$[$a+$b]”
$(())来实现
基本语法
var=$((算数表达式))
使用案例
a=1 b=2 sum=$(($a+$b))
$(expr arg1 arg2 arg3....)来实现
基本语法
sum=$(expre num + num2 )
使用注意
这里的arg1、arg2、arg3都是通过参数传递的方式进行的,所以他们之间必须有空格,否则报错。注意操作符的转义,比如乘法*号,在bash中有特殊含义,需要进行转义
使用案例
bash中的增强性赋值
+=:增强型加等赋值
*=:增强型乘等赋值
-=:增强型减等赋值
/=:增强型除等赋值
%=:增强型取模等赋值
注意:
如果要使用增强赋值语句,等实用let命令的算术运算
自增或自减运算
++:自增运算
--:自减运算
问题案例
计算/etc/passwd文件中的第10个用户和第20个用户的UID之和
[root@oldboy ~]# u1=$(head -n 10 /etc/passwd|tail -n 1 |cut -d : -f3) [root@oldboy ~]# u2=$(head -n 20 /etc/passwd|tail -n 1 |cut -d : -f3) [root@oldboy ~]# echo $u1 10 [root@oldboy ~]# echo $u2 500 [root@oldboy ~]# let sum=$u1+$u2 [root@oldboy ~]# echo $sum 510
传递两个文件作为参数给脚本,计算这个两个文件的所有空白行之和
#!/bin/bash spaceline1=$(grep "^[[:space:]]*$" $1|wc -l) spaceline2=$(grep "^[[:space:]]*$" $2|wc -l) echo "the sum of space line: $[$spaceline1+$spaceline2]"
14、bash中的条件测试
基本介绍
判断某种场景或者某需求是否满足,这就需要测试机制(测试表达式)来实现
专用的测试表达式需要由专门的测试命令来实现
测试命令
test 表达式
[ 表达式 ]
[[ 表达式 ]]
bash的测试类型
数值测试
-gt:左侧是否大于右侧
-ge:左侧是否大于等于右侧
-eq:左侧是否等于右侧
-lt:左侧是否小于右侧
-le:左侧是否小于等于右侧
字符串测试
==:左边字符串是否等于右边字符串
!=:左侧是否不等于右侧(ASCII码进行比较)
<:左侧是否小于右侧
>:左侧是否大于右侧
=~ PATTERN:左侧字符串您是否能够被右侧的PATTERN所匹配
注意:此种测试必须用在[[ ]]测试命令中,否则报错
使用案例
[root@oldboy /]# [ "name" =~ ^n.*m$ ] -bash: [: =~: binary operator expected [root@oldboy /]# [[ "name" =~ ^n.*m$ ]] [root@oldboy /]# echo $? 1 [root@oldboy /]# [[ "name" =~ ^n.*e$ ]] [root@oldboy /]# echo $? 0
-z string:string字符串是否为空,空为真,不空为假
-n string:测试字符串是否为空,空为假,不空为真
注意
进行字符串比较时,尽量都使用引号引起来,避免出错
在使用等于、大于、小于、不等于等去判断两个字符串是否相等时,在这个判断的等于、大于、小于、不等于的左右两边必须加空格(不管是用的[ ],还是用的[[ ]]),与字符串相隔开,否则会出现意想不到的效果
文件测试
文件存在性测试
-a FILE:如果测试的文件存在则为真
-e FILE:如果文件存在则为真,不存在则为假
-f FILE:如果文件存在且为普通文件则为真,否则为假
文件类别测试
-b FILE:文件存在且为块设备文件则为真,否则为假
-c FILE:文件存在且为字符设备文件则为真,否则为假
-d FILE:文件存在且为目录文件则为真,否则为假
-p FILE:文件存在且为命名管道则为真,否则为假
-S FILE:文件存在且为套接字文件则为真,否则为假
-h FILE:文件存在且为链接符号文件则为真,否则为假
文件特殊权限测试
-g FILE:文件存在且文件属性被设置了sgid则为真,否则为假
-u FILE:文件存在且拥有suid权限则为真,否则为假
-k FILE:文件存在且拥有sticky权限则为真,否则为假
文件权限测试
-r FILE:文件存在且可读则为真,否则为假
-w FILE:文件存在且可写则为真,否则为假
-x FILE:文件存在且可执行则为真,否则为假
文件大小测试
-s FILE:文件存在且非空则为真,否则为假
文件打开性测试
-t fd:fd表示文件描述符是否已经打开且与某终端相关
-N FILE:文件自从上一次被读取过后是否被修改(文件被修改包含两种情况,一种是自己手动使用文件查看工具修改,另一种被重定向了)
-O FILE:当前有效用户是否为文件的属主
-G FILE:当前有效用户是否为文件的属组
文件与文件之间的测试
FILE1 -ef FILE2 :通过查看两个文件的inode是否相同来判断两个文件是否相同,相同为真,否则为假
FILE1 -nt FILE2:FILE1是否比FILE2新,比较两个文件的最近一次修改时间,即修改mtime
FILE1 -ot FILE2:FILE1是否比FILE2旧,比较两个文件的最近一次修改时间,即修改mtime
组合条件测试
组合条件测试其实就是逻辑运算
逻辑运算的两种方式
&&:表示并且
语法
COMMAND1 && COMMAND2
||:表示或者
语法
COMMAND1 || COMMAND2
!:表示非
语法
! COMMAND
组合条件测试的另一种方式
[ EXPRESSION -a EXPRESSION2 ]:表达式1成立并且表达式2成立,则为真
[ EXPRESSION -o EXPRESSION2 ]:表达式1成立或者表达式2成立,则为真
-a:表示并且
-o:表示或者
使用注意
在bash中一个中括号表示命令,两个中括号内嵌表示关键字。同时中括号中的表达式两边必须要有空格,否则报错
使用案例
[root@oldboy /]# [ 1 -gt 2 ] [root@oldboy /]# echo $? 1 [root@oldboy /]# [ "name" == "name" ] [root@oldboy /]# echo $? 0
关于条件是测试中linux对这方面存在的问题
在管理员权限下,当将一个文件的所有读写执行全部去掉,然后在进行文件的读写执行条件测试时会出现诡异的情况,那就是无论怎么测试,没有读写执行权限的文件,在管理员眼中都是不存在的,意思就是,即使你设置了文件的所有权限都没有,我依然能够读写执行文件。下面就是关于这个问题的详细解释过程:
[root@oldboy scripts]# cp /etc/fstab /tmp/file1.txt [root@oldboy scripts]# chmod -rw /tmp/file1.txt [root@oldboy scripts]# ll /tmp/file1.txt ----------. 1 root root 781 Mar 7 16:12 /tmp/file1.txt [root@oldboy scripts]# [ ! -r /tmp/file1.txt -a ! -w /tmp/file1.txt ] [root@oldboy scripts]# echo $? 1 [root@oldboy scripts]# [ ! -r /tmp/file1.txt -o ! -w /tmp/file1.txt ] [root@oldboy scripts]# echo $? 1 [root@oldboy scripts]# [ ! -r /tmp/file1.txt ] && [ ! -w /tmp/file1.txt ] [root@oldboy scripts]# echo $? 1 [root@oldboy scripts]# [ ! -r /tmp/file1.txt ] || [ ! -w /tmp/file1.txt ] [root@oldboy scripts]# echo $? 1 [root@oldboy scripts]# [ ! -r /tmp/file1.txt ] [root@oldboy scripts]# echo $? 1 [root@oldboy scripts]# [ ! -w /tmp/file1.txt ] [root@oldboy scripts]# echo $? 1 [root@oldboy scripts]# su - oldboy [oldboy@oldboy ~]$ [ ! -r /tmp/file1.txt ] [oldboy@oldboy ~]$ echo $? 0 [oldboy@oldboy ~]$ [ ! -r /tmp/file1.txt ] && [ ! -w /tmp/file1.txt ] [oldboy@oldboy ~]$ echo $? 0 [oldboy@oldboy ~]$ [ ! -r /tmp/file1.txt -a ! -w /tmp/file1.txt ] [oldboy@oldboy ~]$ echo $? 0 [oldboy@oldboy ~]$ [ ! ( -r /tmp/file1.txt -o -w /tmp/file1.txt ) ] [oldboy@oldboy ~]$ echo $? 0
15、bash自定义退出状态码
基本介绍
脚本退出一般都会有退出码,告诉管理员我们的脚本执行情况
基本语法
exit [n]
使用注意
脚本中一旦遇到exit命令,脚本立即终止,终止退出状态取决于exit命令后边的数字
如果为给脚本指定相应的退出码,否则整个脚本的退出状态码取决于脚本执行的最后一条命令
使用案例
写一个脚本接受一个文件路径作为参数,脚本执行时判断参数个数是否小于1,小于1则提示用户至少输入一个参数。如果参数个数不小于1,则显示第一个参数文件中的空白行
#!/bin/bash [ -z "$1" ] && { echo "USAGE:$1 file" exit 1 } [ $# > 1 ] && { w=$(grep -E "^[[:space:]]*$" $1|wc -l) echo "$1 has space lines:$w" }
4、bash内建的随机数生成器
基本介绍
bash内建了随机数生成器,能够生成随机数,其实这个生成器他是一个环境变量
基本语法
$RONDOM
使用案例
[root@oldboy ~]# echo $(($RANDOM%60)) 38 [root@oldboy ~]# echo $(($RANDOM%60)) 5 [root@oldboy ~]# echo $(($RANDOM%60)) 35
未完,待续......