本文目录结构:
一、变量
- 用户自定义变量
- Bash 环境变量
- Bash 语系变量
- 位置参数变量
- 预定义变量
二、运算符
- declare 命令
- 数值运算方法
三、环境变量配置文件
- 简介
- 功能
四、正则表达式
- 通配符与正则表达式
- 基础正则表达式
- 之前的笔记
五、字符截取命令
- cut 命令
- printf 命令
- awk 命令
- sed 命令
- 字符处理命令(sort和wc)
一、变量
变量是计算机内存的单元,其中存放的值可以改变,一般用一个比较好记的单词来作为变量名。
-
变量命名规则是:
- 由字母、数字和下划线的字符串组合且不能由数字开头
- 长度不超过 255 字符
- 在有效范围内是唯一的(一般在一个程序中是唯一的)
- 在 bash 中,变量的默认类型都是字符串类型(哪怕你存的是整数123,他也认为是字符串123)
- 变量的命名一般要具有一定含义
-
在
Shell
中,所有的变量都是字符串类型,即每个变量存储的内容都是以字符串的形式放在内存单元中,如age=18
,18
不是数字而是字符串18
!所以不能简单的对变量进行数值运算。不像其他语言一样有整型、浮点型、字符型等变量。 -
在 shell 中主要分为以下 3 种变量:
- 用户自定义变量:用户可以任意定义的变量,用户对该变量拥有所有权限。最自由,可以改变变量名和作用和值
- 环境变量:有 2 类,第一类环境变量可以被用户自定义,对 Linux 系统没有影响;第二类环境变量是系统已经定义好的环境变量,我们可以去改变某个环境变量的值(但不能改变量名),从而对系统产生影响。
- 预定义变量:bash中定义好的,不能更改变量名和作用,只能改值。
下面详细介绍以上几种变量:
1. 用户自定义变量
-
定义变量的格式:
变量名 = 变量值
如:name="New Bee" 需要注意的是: 1. 定义变量的时候,不能在等号两边加空格,不然系统会将这条语句识别为命令 2. 若变量的值含有空格,则需用引号括起来(单双引号都行)
其中,单双引号的区别:
1. 单引号:单引号括起来的内容,特殊符号无特殊意义,仅表现为普通字符 2. 双引号:双引号括起来的内容,特殊符号具有意义,如 `$` 符号等
-
调用变量的方式:
$变量名
如:echo $name
例子:
[root@localhost ~]# x=5 [root@localhost ~]# y=6 [root@localhost ~]# z=$x+$y [root@localhost ~]# echo $z 5+6 本例表明:Bash 中的变量都是字符串类型
-
变量的叠加:
有时候不想替换变量,而是在变量后面加上新的东西,可以利用变量的叠加:
变量叠加的方式有 2 种:
x="$x"str
或x=${x}str
,如下例所示[root@localhost ~]# x=123 [root@localhost ~]# echo $x 123 [root@localhost ~]# x="$x"456 [root@localhost ~]# echo $x 123456 [root@localhost ~]# x=${x}789 [root@localhost ~]# echo $x 123456789
-
变量的查看:
用
set
命令即可查看当前系下的所有已经生效的变量,包括环境变量和自定义变量。 -
变量的删除:
用
unset xxx
命令即可删除名为xxx
的变量。如unset name
2. bash 环境变量
2.1 两种环境变量
-
用户自定义变量与环境变量的区别:
用户自定义变量是局部变量,只能在自己的 shell 环境中生效;环境变量是全局变量,能在自己的 shell 和子 shell 中生效。或者说,你在当前 shel 中定义了一个环境变量和一个用户自定义变量,那么你可以在当前 shell 中编写的程序里调用该环境变量而不能调用该用户自定义变量。
Bash 中有 2 种环境变量:用户自定义的环境变量,系统环境变量。
-
用户自定义的环境变量:
设置环境变量有 2 种方式:
export 变量名=变量值
;如:export x=5
- 先定义变量再 export 变量名,如:
x=5
->export x
-
系统环境变量:
对系统生效的常用环境变量(都是大写,建议都写成大写):
HOSTNAME:主机名 SHELL:当前的 shell 环境 TERM:终端环境 HISTSIZE:历史命令条数 SSH_CLIENT:若当前操作环境是用 ssh 连接的,这里记录客户端 IP SSH_TTY:ssh 连接的终端时 pts/1 USER:当前登录的用户 LANG:当前 shell 的语言环境
2.2 PATH 和 PS
本篇重点介绍的环境变量:PATH
和 PS
-
PATH(系统搜索命令路径)
系统在执行某个脚本的时候,标准的执行方法是使用绝对路径或相对路径调用该脚本,在 Linux 系统中,每个命令实际上都是一个程序,所以标准的执行命令的方法也是使用绝对路径和相对路径,但是我们在敲命令的时候并没有加上绝对路径,是因为 PATH 环境变量的功能。
当我们执行命令时,系统会去 PATH 所定义的路径中查找该脚本程序,若找到则执行,若找不到则报错。所以我们有 2 种方法可以不加路径执行脚本:
1. 将脚本复制到 PATH 变量所包含的某一个路径下; 2. 将脚本所在路径叠加到 PATH 环境变量中。
-
PS1(当前系统提示符)
[root@localhost /]# set | grep PS1 PS1='[u@h W]$ '
PS1 能识别的反斜杠转义符有:
d 显示日期,格式为 "星期 月 日" H 显示完整主机名(默认完整主机名为"localhost.localdomain") h 显示主机名 显示 24 小时制时间,格式为 "HH:MM:SS" A 显示 24 小时制时间,格式为 "HH:MM" u 显示当前用户名 w 显示当前所在目录的完整名称 W 显示当前所在目录的最后一个目录 $ 提示符,root 用户显示 "#",普通用后显示 "$"
设置系统提示符:
PS1='[u@h w]$ '
其他 PS 命令:
[root@localhost /]# set | grep PS2 PS2='> ' 实际上是一个换行输入的符号,当你命令没输完要换行输入的时候的提示符号
-
查看环境变量:
env
命令;删除环境变量:unset xxx
3. bash 语系变量
我们的母语是汉语,即中文语系,但是在很多系统中使用的是英文语系,所以我们就会很好奇说某个系统到底支不支持中文显示。所以这一节用来介绍系统语系。
-
查看当前系统支持哪些语系:
locale
命令[root@localhost /]# locale LANG=zh_CN.UTF-8 LC_ALL=
其中,LANG 变量是当前系统语系,
zh_CN.UTF-8
是中文语系;LC_ALL 变量是系统默认语系,即下次开机启动后系统使用的语系。 -
查看当前系统使用的语系:
echo $LANG
-
查看 Linux 系统支持的所有语系
locale -a
-
查看默认语系:
cat /etc/sysconfig/i18n
,是系统启动时选择的语系
4. 位置参数变量
我们在运行脚本的时候,一般会在后面跟上几个参数,用来对脚本中的程序传入几个值。这些参数就叫做位置参数,而存放这些参数的变量就叫做位置参数变量。
位置参数变量主要有 4 种:$n
,$*
,$@
和 $#
。
其中:
$n n 为数字,0 代表命令本身,1-9 代表后面跟的参数
$* 这个变量代表命令行中所有的参数,$* 把所有参数看成一个整体
$@ 这个变量代表命令行中所有的参数,$@ 把所有参数分开对待
$# 这个变量代表命令行中的所有参数的个数
5. 预定义变量
$? 最后一次命令执行的返回状态,0 代表命令被正确执行,非 0 代表命令没有被正确执行
如 && 和 || 就是根据前一条命令的 $? 进行判断
$$ 返回当前进程的进程号
$! 返回后台运行的最后一个进程的进程号
这里再介绍一个 read
变量,用来提示用户的输入。如果系统管理员写了一个脚本,但是该脚本的执行方法其他人是不知道的,为了让其他人也能正确执行该脚本,需要在执行脚本的时候给出提示,让执行者按照提示输入正确的信息。这就是 read
变量的作用。如下例所示:
[root@localhost sh]# cat read.sh
#!/bin/bash
# 提示用户输入名字,并指定 10 秒超时
read -p "please input your name:" -t 10 name
echo $name
# 提示用户输入密码,并隐藏输入信息
read -s -p "please input your passwd:" passwd
echo -e "
$passwd"
# 提示用户输入性别,并限制输入的个数
read -p "please input your sex [B/G]:" -n 1 sex
echo -e "
$sex"
其中,read 的用法是:
格式:read [选项] [变量名]
[选项]:
-p 显示提示信息
-s 隐藏输入内容
-t 设置输入超时(默认是秒)
-n 限制输入的字符个数
二、运算符
1. declare 命令
这条命令用来声明变量类型。
在 Linux 中,所有变量都默认是字符型,但是字符型变量不能进行数值运算,所以我们需要一个声明变量类型的方法,来声明某个变量是数值类型,这样才能对变量进行数值运算,就是本节将要介绍的 declare
命令。当然了,declare
命令不仅仅能将变量改成数值类型,还可以改成其他很多类型。
-
命令格式:
declare [+/-] [选项] 变量名
其中:
+ 取消变量的类型(恢复到字符类型) - 给变量添加类型 [选项]: -i 整型 -a 数组类型 -x 环境变量 -r 只读变量 -p 查看变量类型
-
例子:
1. 定义整型: [root@localhost /]# x=5 [root@localhost /]# y=6 [root@localhost /]# declare -i z=$x+$y [root@localhost /]# echo $z 11 2. 定义数组: [root@localhost ~]# movie[0]=1 [root@localhost ~]# movie[1]=2 [root@localhost ~]# declare -a movie[2]=3 实际上,当我们使用 movie[] 为其赋值时,就已经认为这是一个数组变量了 3. 查看数组: [root@localhost ~]# echo ${movie} # 打印第一个 1 [root@localhost ~]# echo ${movie[2]} # 打印第 2+1 个 3 [root@localhost ~]# echo ${movie[*]} # 打印所有 1 2 3 4. 定义环境变量: [root@localhost ~]# declare -x text=123 [root@localhost ~]# env | grep text text=123 实际上,用 export 命令来定义环境变量时,export 也是用 declare 方法来实现的 5. 定义只读变量: [root@localhost ~]# declare -r text # 只读属性的变量,不可改变值,不可删除,不可用 +r 取消属性 6. 查看整型的变量有哪些: [root@localhost ~]# declare -p -i declare -i a="10"
2. 数值运算的方法
由于使用 declare
给变量进行数值运算比较繁琐(declare -i c=$a+$b
),故介绍另外的数值运算方法:
-
第一种:
d=$(expr $a + $ b) # + 号两边必须有空格,感觉也繁琐
-
第二种:
e=$[$a+$b] # + 号两边有没有空格无所谓,格式简单
-
第三种:
f=$(($a+$b)) # + 号两边有没有空格无所谓,格式简单,推荐使用
-
运算符的优先级
三、环境变量配置文件
1. 简介
-
环境变量的作用:
定义每个用户的操作环境,如 PATH 用于查找命令路径的变量;PS1 命令提示符的变量。修改环境变量配置文件后,必须注销重新的登录才能生效,但是我们不想这么麻烦,可以使用
source
命令。 -
source 命令:
作用:可以不用注销重新登陆即可是修改后的环境变量配置文件生效。
格式:source
配置文件 或. 配置文件
-
环境变量配置文件的作用:
将环境变量写进环境变量配置文件,这样在系统启动的时候就可以通过环境变量配置文件自动加载环境变量,而不需要管理员手动配置。其主要定义的是默认的环境变量,如 PATH 等。
-
常见的环境变量配置文件:
/etc/profile /etc/profile.d/*.sh /etc/bashrc ~/.bash_profile ~/.bashrc
-
系统启动时加载环境变量配置文件的顺序:
如下图所示:
其中,绿色箭头为正常登录过程,蓝色箭头为非正常登录过程。正常登录是指:登录时输入用户名和密码;非正常登录是指:如 root 用户通过 sudo 命令切换用户(root -> user)。
2. 功能
对以上介绍的环境变量配置文件做详细的功能介绍:
2.1 /etc/profile 文件
这个文件的主要功能有:
-
定义了如下变量:
USER变量 LOGNAME变量 MAIL变量 PATH变量 HOSTNAME变量 HISTSIZE变量 umask变量
-
其中 umask 变量:
umask
变量定义了该用户的默认创建权限,即该用户创建文件或文件夹时,该文件或文件夹的权限。其中:文件最高权限为 666,文件夹最高权限为 777,创建后的文件权限是:最高权限与 umask 权限转换成 wrx 后再相减。
如下例所示:创建文件 touch abc 其默认权限应该是:666 对应的 rw-rw-rw- 减去 umask 022 对应的 ----w--w- 等于 rw-r--r--
所以可以理解成
umask
权限是系统中准备丢弃的权限。 -
调用
./etc/profile.d/*.sh
文件 -
调用
~/.bash_profile
文件
2.2 /etc/profile.d/*.sh 文件
这些文件分别是:
colorls.csh
colorls.sh
glib2.csh
glib2.sh
lang.csh
lang.sh
less.csh
less.sh
vim.csh
vim.sh
which2.sh
其中,/etc/profile.d/lang.sh
文件调用 /etc/sysconfig/i18n(定义了系统默认语系的文件)
文件。
2.3 ~/.bash_profile 文件
这个文件的作用就是:
- 调用
~/.bashrc
文件 - 在 PATH 变量之后叠加
:$HOME/bin
这个目录
2.4 ~/.bashrc 文件
这个文件的作用是:
- 定义一些别名
- 调用
/etc/bashrc
文件
2.5 /etc/bashrc 文件
这个文件的作用是:
-
定义了如下变量
① 若用户正常登录:
PS1
变量
② 若非正常登录:umask
变量,PATH
变量,PS1
变量 -
判断:
① 若用户正常登录:调用
/etc/profile.d/*.sh
文件
② 若非正常登录:所有环境变量配置文件生效并进入系统
2.6 常见错误:用户提示符异常
现象:正常登录的一般情况下,用户提示符为 [root@localhost ~]#
,有时一些异常情况会导致用户提示符变成类似 bash5.2#
的 Linux 内核默认提示符,是由于系统启动过程中环境变量配置文件 /etc/bashrc
未被调用,可能是之前的一些环境变量配置文件如 ~/.bashrc
不存在或内容有错。
解决办法:去另外一台 Linux 设备上拷贝相关文件
3. 其他环境变量配置文件
-
注销时生效的环境变量配置文件
~/.bash_logout
,该文件针对单个用户,默认为空,不执行任何操作可以在里面加入命令使其清空历史命令:
history -C
-
存放用户历史命令的环境变量配置文件
~/.bash_history
, 存放在硬盘中 -
登录时提示警告信息的文件:
/etc/issue
,只对本地终端起作用,远程登录不显示 -
登录时提示警告信息的文件:
/etc/issue.net
,对远程终端起作用,但是转义符失效是否在远程终端显示警告信息,由 ssh 的配置文件
/etc/ssh/sshd_config
决定,加入Banner /etc/issue.net
才能显示(同时要重启:service sshd restart
) -
登录时提示警告信息的文件:
/etc/motd
,既对本地又对远程终端起作用,建议使用这种方式这个文件的作用是在登录之后显示,而前两个在登陆之前显示
四、正则表达式
正则表达式是 shell 编程中的核心,而且正则表达式在几乎所有的语言中都有用到。正则表达式实际上就是一种描述字符串排列和匹配的语法规则,主要用于字符串的分隔、匹配、查找和替换等操作,其中最主要的是匹配!
1. 通配符与正则表达式
-
通配符
通配符用来匹配符合条件的文件名称,属于 完全匹配,如
ls
find
cp
这些命令是不支持正则表达式的,所以只能用 shell 自己的通配符来进行匹配了。shell 当中的通配符一共有 3 个:*
、?
和[]
。其中:* 匹配任意字符,字符可有可无 ? 匹配任意单个字符,必须占一个字符 [] 匹配括号中的一个字符
-
正则表达式
正则表达式用来在文件中匹配符合条件的字符串,是属于 包含匹配。写的正则表达式越长匹配的范围越小。如
grep
awk
sed
这些命令可以支持正则表达式。 -
二者的区别(3个)
通配符用来匹配文件名,正则表达式用来匹配文件中的字符串
通配符是完全匹配,正则表达式是包含匹配
搜索字符串的命令能够识别正则表达式,搜索文件名的命令不能识别。
2. 基础正则表达式
-
基础正则表达式如下:
-
例子:
匹配日期格式:
YYYY-MM-DD
[0-9]{4}-[0-9]{2}-[0-9]{2}
,不过类似2017-45-37
和19581-10-10
这样的字符串也会匹配到,所以只能匹配格式而不能判断是否合法。匹配 IP 地址格式:
[0-9]{0,3}.[0-9]{0,3}.[0-9]{0,3}.[0-9]{0,3}
,不过不合法的 IP 地址也会被匹配到,所以只能匹配格式而不能判断是否合法。
3. 之前的笔记
2.1)-- * 匹配 "*" 前一个字符 0 到任意多次
2.2)-- . 匹配除了换行符之外的任意一个字符(类似通配符的?)
① a..d 匹配 a 开头 d 结尾并且 a 和 d 之间有两个任意字符的字符串
② a.*d 匹配 a 开头 d 结尾并且 a 和 d 之间有任意多个任意字符的字符串
③ .* 匹配所有内容
2.3)-- "^" 代表行首 "$" 代表行尾
① grep "^a" filename 匹配以 a 开头的行
② grep "f$" filename 匹配以 f 结尾的行
③ grep "^$" filename 匹配空白行
2.4)-- [] 和通配符的 [] 一样,只能匹配中括号中的任意一个字符
① [A-Za-z] 大写 A 到小写 z
② [0-9] 0 到 9
③ ^[^0-9] 匹配不以 0 到 9 开头的行
注意:"^"在中括号之外代表行首,中括号之内代表取反
2.5)-- "" 转义符:取消符号的特殊意义
① ".$" 代表以 "." 结尾的行
2.6)-- {n} 匹配其前面的字符刚好出现 n 次
① grep "a{3}" filename 匹配连续出现 3 次 a 的行
② grep "[0-9]{3}" filename 匹配连续出现 3 次数字的行
③ 因为是包含匹配,所以若想精确匹配要添加"定位符",如:grep "^a{3}$" filename
3、区别:
3.1)用处:
-- 通配符用于查找文件
-- 正则表达式用于查找文件里面的内容
3.2)效果:
-- 通配符是完全匹配
-- 正则表达式是包含匹配
五、字符截取命令
1. cut 命令
cut
是列提取命令,且默认以制表符为分隔符。
命令格式:cut [选项] [参数] 文件名
cut [选项] [参数] 文件名
[选项]:
-d 手动指定分隔符
-f 指定列号,如 2,4 代表第 2 和第 4 列而不是第 2 到第 4 列
-c 以字符以单位
-b 以字节为单位
例子:从 /etc/passwd
中截取普通用户的用户名和用户ID
cut -d ':' -f 1,3 /etc/passwd | grep '/bin/bash' | grep -v 'root'
2. printf 命令
printf
命令是一个标准输出命令,比较麻烦,但是 awk
需要用到,不得不学。
命令格式:printf '输出类型输出格式' 输出内容
其中:
输出类型:
%ns 输出字符串,n 是指输出几个字符
%ni 输出整数,n 是指输出几个数字
%m.nf 输出浮点数,m 和 n 是数字,如 %8.2f 代表共输出 8 位数其中 2 位是小数
输出格式:
a 输出警告声音
输出退格键,即 backspace 键
f 清除屏幕
换行
回车,即 enter 键
制表符,即 tab 键
v 垂直制表符,即竖着的 tab 键
例子:
[root@localhost ~]# printf '%s %s %s
' 1 2 3 4 5 6
1 2 3
4 5 6
[root@localhost ~]# printf '%8.2f' 123456.78
123456.78
其中,命令中的单引号不能省略
print
和 printf
的区别是:1. 前者自动换行,后者不自动换行;2. 前者是 awk 中的命令,后者是 Linux 中的命令
3. awk 命令
格式:awk '条件1{动作1} 条件2{动作2}..' 文件名
awk '条件1{动作1} 条件2{动作2}..' 文件名
条件(Pattern):
一般用关系表达式作为条件
x>10
x>=10
动作(Action):
格式化输出,当动作是格式化输出时,注意要加 双引号,单引号都不行
流程控制语句
其中:条件可省略,当没有条件时,无条件执行动作
关系表达式:
-
BEGIN:
在所有的动作执行之前先执行的动作,比如 awk 'BEGIN{FS=":"}{print $1 " " $3}' ,在将读取的那一行赋给 $1 和 $3 之前先指定分隔符为冒号;
加了 BEGIN 和没加 BEGIN 的情况如下:
[root@localhost temp]# cat /etc/passwd | grep /bin/bash | awk '{FS=":"} {print $1 " " $3}' root:x:0:0:root:/root:/bin/bash user1 500 user2 501 [root@localhost temp]# cat /etc/passwd | grep /bin/bash | awk 'BEGIN{FS=":"} {print $1 " " $3}' root 0 user1 500 user2 501
-
END:
与 BEGIN 类似,END 是在执行完了所有的动作后才执行 END 后的动作:
[root@localhost temp]# cat /etc/passwd | grep /bin/bash | awk 'END{FS=":"} {print $1 " " $3}' root:x:0:0:root:/root:/bin/bash user1:x:500:500::/home/user1:/bin/bash user2:x:501:501::/home/user2:/bin/bash
-
内置变量:
$0 代表整个当前行 $n 代表第 n 个字段 NR 每行的记录号(行号) NF 字段数量变量(总列数) FILENAME 当前正在处理的文件,管道符情况下为 -
-
例子:
# 显示 /etc/passwd 每行的行号,每行的列数以及对应行的用户名 [root@localhost temp]# awk 'BEGIN{FS=":"}{print NR,NF,$1}' /etc/passwd # 显示 /etc/passwd 中用户 ID 大于 100 的行号和用户名(if...else...) [root@localhost temp]# awk 'BEGIN{FS=":"}{if ($3>10) print NR,$1}' /etc/passwd #
4. sed 命令
实际上 sed
命令严格来说不是字符截取命令,而是修改字符的命令。
命令格式:sed [选项] '[动作]' 文件名
sed [选项] '[动作]' 文件名
[选项]
-n 只打印改动的数据所在行打印到屏幕,否则将所有数据都打印到屏幕
-e 允许对输入数据应用多个动作
-i 将修改保存到文件中,一般是只输出到屏幕
[动作]
-a 行后追加,在当前行后添加一行或者多行
-c 行替换,用 c 后面的字符串替换原数据行
-i 行前插入,在当前行前添加一行或者多行
-p 打印,输出指定的行
-s 字符串替换,格式:"行范围s/旧字符串/新字符串/g",其中 g 代表该范围中若有多个旧字符串都替换成新字符串,否则只替换第一个
例子:
-
比较 sed '2p' student.txt 和 sed -n '2p' student.txt 的区别,验证 -n 的作用
[root@localhost temp]# sed '2p' student.txt ID NAME GENDER MARK 1 furong F 85 1 furong F 85 2 fengj F 60 3 cang F 70 [root@localhost temp]# sed -n '2p' student.txt 1 furong F 85
-
验证动作
-i
的作用:sed '2d' student.txt # 会输出没有第二行的 student.txt ,但没有作用于源文件因为没加 -i sed '2,5d' student.txt # 2,5 是作用 2 到 5 行而不是"和"
-
使用动作
-s
进行替换sed '2c shell' student.txt # 将第二行换为 "shell" sed '2s/yhl/shell/' student.txt # 将第二行的 "yhl" 替换为 "shell" sed '2s/yhl/shell/g' student.txt # 将第二行中如果有多个 "yhl" 都替换为 "shell"
-
用
-e
选项执行多条动作sed -e '2s'sed -e '2s/furong//g;3s/fengj//g' student.txt # 动作之间用分号 `;` 隔开
5. 字符处理命令(排序和统计)
5.1 sort 排序命令
sort
命令用于对文件中的字符串或者数据进行排序。
命令格式:sort [选项] 文件名
sort [选项] 文件名
[选项]
-f 忽略大小写
-n 以数值型进行排序(默认使用字符串型)
-r 反向排序
-t 指定分隔符(默认分隔符是制表符)
-k n[,m] 按照指定的字段范围排序,从第 n 字段开始到 m 字段结束(默认到行尾)
例子:
[root@localhost ~]# sort [-r] /etc/passwd # 默认按照字符型以行为单位进行排序,-r 是反向排序
[root@localhost ~]# sort -t ":" -k 3,3 -n /etc/passwd # 使用 ":" 作为分隔符,并且按数值型以第 3 个字段进行排序
5.2 wc 统计命令
命令格式:wc [选项] 文件名
wc [选项] 文件名
[选项]:
-l 统计行数
-w 统计单词数
-c 统计字符数(换行制表也算)