shell基础
一、Shell概述
1、什么是Shell
shell的分类
Shell类别 | 易学性 | 可移植性 | 编辑性 | 快捷性 |
---|---|---|---|---|
Bourne Shell (sh) | 容易 | 好 | 较差 | 较差 |
Korn Shell (ksh) | 较难 | 较好 | 好 | 较好 |
Bourne Again (Bash) | 难 | 较好 | 好 | 好 |
POSIX Shell (psh) | 较难 | 好 | 好 | 较好 |
C Shell (csh) | 较难 | 差 | 较好 | 较好 |
TC Shell (tcsh) | 难 | 差 | 好 | 好 |
hell的两种主要语法类型有Bourne和C,这两种语法彼此不兼容。Bourne家族主要包括sh、ksh、Bash、psh、zsh;C家族主要包括:csh、tcsh (Bash和zsh在不同程度上支持csh 的语法)。
我们可以通过/etc/shells文件来查询Linux支持的Shell。命令如下:
1 | [root@localhost ~]# vi /etc/shells |
二、Shell脚本的执行方式
1、echo命令
1 | [root@localhost ~]# echo [选项] [输出内容] |
-n:取消输出后行末的换行符号(就是内容输出后不换行)
1 | 例子1: |
在echo命令中如果使用了“-e”选项,则可以支持控制字符,如表所示:
控制字符 | 作用 |
---|---|
\ | 输出\本身 |
\a | 输出警告音 |
\b | 退格键,也就是向左删除键 |
\c | 取消输出行末的换行符。和“-n”选项一致 |
\e | ESCAPE键 |
\f | 换页符 |
\n | 换行符 |
\r | 回车键 |
\t | 制表符,也就是Tab键 |
\v | 垂直制表符 |
\0nnn | 按照八进制ASCII码表输出字符。其中0为数字零,nnn是三位八进制数 |
\xhh | 按照十六进制ASCII码表输出字符。其中hh是两位十六进制数 |
1 | 例子3: |
也就是说141这个八进制,在ASCII码中代表小写的“a”,其他的以此类推。
1 | 例子7: |
echo命令还可以进行一些比较有意思的东西,比如:
1 | 例子8: |
这条命令会把abcd按照红色输出。解释下这个命令\e[1是标准格式,代表颜色输出开始,\e[0m代表颜色输出结束,31m定义字体颜色是红色。echo能够识别的颜色如下:30m=黑色,31m=红色,32m=绿色,33m=黄色,34m=蓝色,35m=洋红,36m=青色,37m=白色。
1 | 例子9: |
这条命令会给abcd加入一个绿色的背景。echo可以使用的背景颜色如下:40m=黑色,41m=红色,42m=绿色,43m=黄色,44m=蓝色,45m=洋红,46m=青色,47m=白色。
2、Shell脚本的执行
1 | [root@localhost sh]# vi hello.sh |
Shell脚本写好了,那么这个脚本该如何运行呢?在Linux中脚本的执行主要有这样两种种方法:
- 赋予执行权限,直接运行这
种方法是最常用的Shell脚本运行方法,也最为直接简单。就是赋予执行权限之后,直接运行。当然运行时可以使用绝对路径,也可以使用相对路径运行。命令如下:
1 | [root@localhost sh]# chmod 755 hello.sh |
- 通过Bash调用执行脚本
这种方法也非常简单,命令如下:
1 | [root@localhost sh]# bash hello.sh |
三、Bash的基本功能
1、历史命令
1)历史命令的查看
1 | [root@localhost ~]# history [选项] [历史命令保存文件] |
1 | [root@localhost ~]# vi /etc/profile |
我们使用history命令查看的历史命令和/.bash_history文件中保存的历史命令是不同的。那是因为当前登录操作的命令并没有直接写入/.bash_history文件,而是保存在缓存当中的。需要等当前用户注销之后,缓存中的命令才会写入/.bash_history文件。如果我们需要把内存中的命令直接写入/.bash_history文件,而不等用户注销时再写入,就需要使用“-w”选项了。命令如下:
1 | [root@localhost ~]# history -w |
这时再去查询~/.bash_history文件,历史命令就和history命令查询的一致了。如果需要清空历史命令,只需要执行:
1 | [root@localhost ~]# history -c |
2)、历史命令的调用
如果想要使用原先的历史命令有这样几种方法:
- 使用上、下箭头调用以前的历史命令
- 使用“!n”重复执行第n条历史命令
- 使用“!!”重复执行上一条命令
- 使用“!字串”重复执行最后一条以该字串开头的命令
- 使用“!$”重复上一条命令的最后一个参数
2、命令别名
1 | 命令格式: |
既然我们说别名的优先级比命令高,那么命令执行时具体的顺序是什么呢?命令执行时的顺序是这样的:
第一顺位执行用绝对路径或相对路径执行的命令。
第二顺位执行别名。
第三顺位执行Bash的内部命令。
第四顺位执行按照$PATH环境变量定义的目录查找顺序找到的第一个命令。
为了让这个别名永久生效,可以把别名写入环境变量配置文件“~/.bashrc”。命令如下:
1 | [root@localhost ~]# vi /root/.bashrc |
3、Bash常用快捷键
快捷键 | 作用 |
---|---|
ctrl+A | 把光标移动到命令行开头。如果我们输入的命令过长,想要把光标移动到命令行开头时使用。 |
ctrl+E | 把光标移动到命令行结尾。 |
ctrl+C | 强制终止当前的命令。 |
ctrl+L | 清屏,相当于clear命令。 |
ctrl+U | 删除或剪切光标之前的命令。我输入了一行很长的命令,不用使用退格键一个一个字符的删除,使用这个快捷键会更加方便 |
ctrl+K | 删除或剪切光标之后的内容。 |
ctrl+Y | 粘贴ctrl+U或ctrl+K剪切的内容。 |
ctrl+R | 在历史命令中搜索,按下ctrl+R之后,就会出现搜索界面,只要输入搜索内容,就会从历史命令中搜索。 |
ctrl+D | 退出当前终端。 |
ctrl+Z | 暂停,并放入后台。这个快捷键牵扯工作管理的内容,我们在系统管理章节详细介绍。 |
ctrl+S | 暂停屏幕输出。 |
ctrl+Q | 恢复屏幕输出。 |
4、输入输出重定向
1)、Bash的标准输入输出
设备 | 设备文件名 | 文件描述符 | 类型 |
---|---|---|---|
键盘 | /dev/stdin | 0 | 标准输入 |
显示器 | /dev/stdout | 1 | 标准输出 |
显示器 | /dev/stderr | 2 | 标准错误输出 |
2)、输出重定向
类型 | 符号 | 作用 |
---|---|---|
标准输出重定向 | 命令 > 文件 | 以覆盖的方式,把命令的正确输出输出到指定的文件或设备当中。 |
······ | 命令 >> 文件 | 以追加的方式,把命令的正确输出输出到指定的文件或设备当中。 |
标准错误输出重定向 | 错误命令 2>文件 | 以覆盖的方式,把命令的错误输出输出到指定的文件或设备当中。 |
······ | 错误命令 2>>文件 | 以追加的方式,把命令的错误输出输出到指定的文件或设备当中。 |
正确输出和错误输出同时保存 | 命令 > 文件 2>&1 | 以覆盖的方式,把正确输出和错误输出都保存到同一个文件当中。 |
······ | 命令 >> 文件 2>&1 | 以追加的方式,把正确输出和错误输出都保存到同一个文件当中。 |
······ | 命令 &>文件 | 以覆盖的方式,把正确输出和错误输出都保存到同一个文件当中。 |
······ | 命令 &>>文件 | 以追加的方式,把正确输出和错误输出都保存到同一个文件当中。 |
······ | 命令>>文件1 2>>文件2 | 把正确的输出追加到文件1中,把错误的输出追加到文件2中。 |
3)、输入重定向
1 | [root@localhost ~]# wc [选项] [文件名] |
5、多命令顺序执行
多命令执行符 | 格式 | 作用 |
---|---|---|
; | 命令1 ;命令2 | 多个命令顺序执行,命令之间没有任何逻辑联系 |
&& | 命令1 && 命令2 | 当命令1正确执行($?=0),则命令2才会执行当命令1执行不正确($?≠0),则命令2不会执行 |
|| | 命令1 || 命令2 | 当命令1 执行不正确($?≠0),则命令2才会执行当命令1正确执行($?=0),则命令2不会执行 |
6、管道符
1)、行提取命令grep
1 | [root@localhost ~]# grep [选项] "搜索内容" 文件名 |
举几个例子:
1 | [root@localhost ~]# grep "/bin/bash" /etc/passwd |
再举几个例子吧:
1 | [root@localhost ~]# grep -A 3 "root" /etc/passwd |
2)find和grep的区别
find命令是在系统当中搜索符合条件的文件名,如果需要模糊查询,使用通配符(通配符我们下一小节进行介绍)进行匹配,搜索时文件名是完全匹配。
1 | [root@localhost ~]# touch abc |
注意:find命令是可以通过-regex选项识别正则表达式规则的,也就是说find命令可以按照正则表达式规则匹配,而正则表达式是模糊匹配。但是对于初学者而言,find命令和grep命令本身就不好理解,所以我们这里只按照通配符规则来进行find查询。
grep命令是在文件当中搜索符合条件的字符串,如果需要模糊查询,使用正则表达式进行匹配,搜索时字符串是包含匹配。
1 | [root@localhost ~]# echo abc > test |
3)管道符
1 | [root@localhost ~]# ll -a /etc/ | more |
1 | [root@localhost ~]# netstat -an | grep "ESTABLISHED" |
1 | [root@localhost ~]# netstat -an | grep "ESTABLISHED" | wc -l |
1 | [root@localhost ~]# rpm -qa | grep httpd |
7、通配符
通配符 | 作用 |
---|---|
? | 匹配一个任意字符 |
* | 匹配0个或任意多个任意字符,也就是可以匹配任何内容 |
[] | 匹配中括号中任意一个字符。例如:[abc]代表一定匹配一个字符,或者是a,或者是b,或者是c。 |
[-] | 匹配中括号中任意一个字符,-代表一个范围。例如:[a-z]代表匹配一个小写字母。 |
[^] | 逻辑非,表示匹配不是中括号内的一个字符。例如:[^0- 9]代表匹配一个不是数字的字符。 |
1 | [root@localhost tmp]# touch abc |
8、Bash中其他特殊符号
符号 | 作用 |
---|---|
‘’ | 单引号。在单引号中所有的特殊符号,如“$”和“`” (反引号)都没有特殊含义。 |
“” | 双引号。在双引号中特殊符号都没有特殊含义,但是“$”、“`”和“\”是例外,拥有“调用变量的值”、“引用命令”和“转义符”的特殊含义。 |
`` | 反引号。反引号括起来的内容是系统命令,在Bash中会先执行它。和$()作用一样,不过推荐使用$(),因为反引号非常容易看错。 |
$() | 和反引号作用一样,用来引用系统命令。 |
() | 用于一串命令执行时,()中的命令会在子Shell中运行 |
{} | 用于一串命令执行时,{}中的命令会在当前Shell中执行。也可以用于变量变形与替换。 |
[] | 用于变量的测试。 |
# | 在Shell脚本中,#开头的行代表注释。 |
$ | 用于调用变量的值,如需要调用变量name的值时,需要用$name的方式得到变量的值 |
\ | 转义符,跟在\之后的特殊符号将失去特殊含义,变为普通字符。如$将输出“$”符号,而不当做是变量引用。 |
1)、单引号和双引号
1 | [root@localhost ~]# name=sc |
2)反引号
1 | [root@localhost ~]# echo ls |
3)、小括号、中括号和大括号
在介绍小括号和大括号的区别之前,我们先要解释一个概念,那就是父Shell和子Shell。在我们的Bash中,是可以调用新的Bash的,比如:
1 | [root@localhost ~]# bash |
这时,我们通过pstree命令查看一下进程数:
1 | [root@localhost ~]# pstree |
知道了父Shell和子Shell,我们接着解释小括号和大括号的区别。如果是用于一串命令的执行,那么小括号和大括号的主要区别在于:
- ()执行一串命令时,需要重新开一个子shell进行执行
- {}执行一串命令时,是在当前shell执行;
- ()和{}都是把一串的命令放在括号里面,并且命令之间用;号隔开;
- ()最后一个命令可以不用分号;
- {}最后一个命令要用分号;
- {}的第一个命令和左括号之间必须要有一个空格;
- ()里的各命令不必和括号有空格;
- ()和{}中括号里面的某个命令的重定向只影响该命令,但括号外的重定向则影响到括号里的所有命令。
还是举几个例子来看看吧,这样写实在是太抽象了:
1 | [root@localhost ~]# name=sc |
四、Bash的变量和运算符
1、什么是变量
在定义变量时,有一些规则需要遵守:
- 变量名称可以由字母、数字和下划线组成,但是不能以数字开头。如果变量名是“2name”则是错误的。
- 在Bash中,变量的默认类型都是字符串型,如果要进行数值运算,则必修指定变量类型为数值型。
- 变量用等号连接值,等号左右两侧不能有空格。
- 变量的值如果有空格,需要使用单引号或双引号包括。如:“test=”hello world!””。其中双引号括起来的内容“$”、“\”和反引号都拥有特殊含义,而单引号括起来的内容都是普通字符。
- 在变量的值中,可以使用“\”转义符。
- 如果需要增加变量的值,那么可以进行变量值的叠加。不过变量需要用双引号包含”$变量名”或用${变量名}包含变量名 。
例如:
1 | [root@localhost ~]# test=123 |
变量值的叠加可以使用两种格式:“$变量名”或${变量名}
- 如果是把命令的结果作为变量值赋予变量,则需要使用反引号或$()包含命令。
例如:
1 | [root@localhost ~]# test=$(date) |
- 环境变量名建议大写,便于区分。
2、变量的分类
- 用户自定义变量:这种变量是最常见的变量,由用户自由定义变量名和变量的值。
- 环境变量:这种变量中主要保存的是和系统操作环境相关的数据,比如当前登录用户,用户的家目录,命令的提示符等。不是太好理解吧,那么大家还记得在Windows中,同一台电脑可以有多个用户登录,而且每个用户都可以定义自己的桌面样式和分辨率,这些其实就是Windows的操作环境,可以当做是Windows的环境变量来理解。环境变量的变量名可以自由定义,但是一般对系统起作用的环境变量的变量名是系统预先设定好的。
- 位置参数变量:这种变量主要是用来向脚本当中传递参数或数据的,变量名不能自定义,变量作用是固定的。
- 预定义变量:是Bash中已经定义好的变量,变量名不能自定义,变量作用也是固定的。
3、用户自定义变量
1)、变量定义
1 | [root@localhost ~]# 2name="shen chao" |
2)、变量调用
1 | [root@localhost ~]# name="shen chao" |
2)、变量查看
1 | [root@localhost ~]# set [选项] |
4)、变量删除
1 | [root@localhost ~]# unset 变量名 |
4、环境变量
1)、环境变量设置
1 | [root@localhost ~]# export age="18" |
2)、环境变量查询和删除
env命令和set命令的区别是,set命令可以查看所有变量,而env命令只能查看环境变量。
1 | [root@localhost ~]# unset gender |
3)、系统默认环境变量
1 | [root@localhost ~]# env |
env命令可以查询到所有的环境变量,可是还有一些变量虽然不是环境变量,却是和Bash操作接口相关的变量,这些变量也对我们的Bash操作终端起到了重要的作用。这些变量就只能用set命令来查看了,我只列出重要的内容吧:
1 | [root@localhost ~]# set |
- PATH变量:系统查找命令的路径
先查询下PATH环境变量的值:
1 | [root@localhost ~]# echo $PATH |
PATH变量的值是用“:”分割的路径,这些路径就是系统查找命令的路径。也就是说当我们输入了一个程序名,如果没有写入路径,系统就会到PATH变量定义的路径中去寻找,是否有可以执行的程序。如果找到则执行,否则会报“命令没有发现”的错误。
那么是不是我们把自己的脚本拷贝到PATH变量定义的路径中,我们自己写的脚本也可以不输入路径而直接运行呢?
1 | [root@localhost ~]# cp /root/sh/hello.sh /bin/ |
那么我们是不是可以修改PATH变量的值,而不是把程序脚本复制到/bin/目录中。当然是可以的,我们通过变量的叠加就可以实现了:
1 | [root@localhost ~]# PATH="$PATH":/root/sh |
当然我们这样定义的PATH变量只是临时生效,一旦重启或注销就会消失,如果想要永久生效,需要写入环境变量配置文件,我们在“环境变量配置文件”小节中再详细介绍。
- PS1变量:命令提示符设置
PS1是一个很有意思的变量(这可不是SONY的游戏机哦),是用来定义命令行的提示符的,可以安装我们自己的需求来定义自己喜欢的提示符。PS1可以支持以下这些选项:
- \d:显示日期,格式为“星期月日”
- \H:显示完整的主机名。如默认主机名“localhost.localdomain”
- \h:显示简写主机名。如默认主机名“localhost”
- \t:显示24小时制时间,格式为“HH:MM:SS”
- \T:显示12小时制时间,格式为“HH:MM:SS”
- \A:显示24小时制时间,格式为“HH:MM”
- @:显示12小时制时间,格式为“HH:MM am/pm”
- \u:显示当前用户名
- \v:显示Bash的版本信息
- \w:显示当前所在目录的完整名称\W:显示当前所在目录的最后一个目录
- \#:执行的第几个命令
- \$:提示符。如果是root用户会显示提示符为“#”,如果是普通用户会显示提示符为“$”
这些选项该怎么用啊?我们先看看PS1变量的默认值吧:
1 | [root@localhost ~]# echo $PS1 |
在PS1变量中,如果是可以解释的符号,如“\u”、“\h”等,则显示这个符号的作用。如果是不能解释的符号,如“@”或“空格”,则原符号输出。那么我们修改下PS1变量,看看会出现社么情况吧
1 | [root@localhost ~]# PS1='[\u@\t \w]\$ ' |
这里要小心,PS1变量的值要用单引号包含,否则设置不生效。再举个例子吧:
1 | [root@04:50:08 /usr/local/src]#PS1='[\u@\ @ \h \# \W]\$' |
PS1变量可以自由定制,好像看到了点Linux可以自由定制和修改的影子,还是很有意思的。不过说实话一个提示符已经使用习惯了,如果换一个还是非常别扭的,还是改回默认的提示符吧:
1 | [root@04:53 上午 localhost 31 src]#PS1='[\u@\h \W]\$ ' |
- LANG语系变量
LANG变量定义了Linux系统的主语系环境,这个变量的默认值是:
1 | [root@localhost src]# echo $LANG |
这是因为我们Linux安装时,选择的是中文安装,所以默认的主语系变量是“zh_CN.UTF-8”。那么Linux中到底支持多少语系呢?我们可以使用以下命令查询:
1 | [root@localhost src]# locale -a | more |
我们支持这么多的语系,当前系统到底是什么语系呢?使用locale命令直接查询:
1 | [root@localhost src]# locale |
我们还要通过文件/etc/sysconfig/i18n定义系统的默认语系,查看下这个文件的内容:
1 | [root@localhost src]# cat /etc/sysconfig/i18n LANG="zh_CN.UTF-8" |
这又是当前系统语系,又是默认语系,有没有快晕倒的感觉。解释下吧,我们可以这样理解,默认语系是下次重启之后系统所使用的语系,而当前系统语系是当前系统使用的语系。如果系统重启,会从默认语系配置文件/etc/sysconfig/i18n中读出语系,然后赋予变量LANG让这个语系生效。也就是说,LANG定义的语系只对当前系统生效,要想永久生效就要修改/etc/sysconfig/i18n文件了。
说到这里,我们需要解释下Linux中文支持的问题。是不是我们只要定义了语系为中文语系,如zh_CN.UTF-8就可以正确显示中文了呢?这要分情况,如果我们是在图形界面中,或者是使用远程连接工具(如SecureCRT),只要正确设置了语系,那么是可以正确显示中文的。当然远程连接工具也要配置正确的语系环境,具体配置方式可以参考Linux系统安装章节。
那么如果是纯字符界面(本地终端tty1-tty6)是不能显示中文的,因为Linux的纯字符界面时不能显示中文这么复杂的编码的。如果我们非要在纯字符界面显示中文,那么只能安装中文插件,如zhcon等。我们举个例子吧:
1 | [root@localhost src]# echo $LANG |
但如果是纯字符界面呢?虽然我们是中文安装的,但纯字符界面的语系可是“en_US.UTF-8”,如图所示:
那么我们更改下语系为中文,看看会出现什么情况吧:
如果我们非要在纯字符界面中设置中文语系,那么就会出现乱码。怎么解决呢?安装zhcon中文插件吧,安装并不复杂,查询下安装说明应该可以轻松安装。
5、位置参数变量
位置参数变量 | 作用 |
---|---|
$n | n为数字,$0代表命令本身,$1-$9代表第一到第九个参数,十以上的参数需要用大括号包含,如${10}. |
$* | 这个变量代表命令行中所有的参数,$*把所有的参数看成一个整体 |
$@ | 这个变量也代表命令行中所有的参数,不过$@把每个参数区分对待 |
$# | 这个变量代表命令行中所有参数的个数 |
1 | [root@localhost sh]# vi count.sh |
那么还有几个位置参数变量是干嘛的呢?我们在写个脚本来说明下:
1 | [root@localhost sh]# vi parameter.sh |
那么“$”和“$@”有区别吗?还是有区别的,$会把接收的所有参数当成一个整体对待,而$@则会区分对待接收到的所有参数。还是举个例子:
1 | [root@localhost sh]# vi parameter2.sh |
6、预定义变量
预定义变量 | 作用 |
---|---|
$? | 最后一次执行的命令的返回状态。如果这个变量的值为0,证明上一个命令正确执行;如果这个变量的值为非0(具体是哪个数,由命令自己来决定),则证明上一个命令执行不正确了。 |
$$ | 当前进程的进程号(PID) |
$! | 后台运行的最后一个进程的进程号(PID) |
我们先来看看“$?”这个变量,看起来不好理解,我们还是举个例子:
1 | [root@localhost sh]# ls |
接下来我们来说明下“$$”和“$!”这两个预定义变量,我们写个脚本吧:
1 | [root@localhost sh]# vi variable.sh |
7、接收键盘输入
1 | [root@localhost ~]# read [选项] [变量名] |
还是写个例子来解释下read命令:
1 | [root@localhost sh]# vi read.sh |
8、Shell的运算符
1)数值运算的方法
那如果我需要进行数值运算,可以采用以下三种方法中的任意一种:
- 使用declare声明变量类型
既然所有变量的默认类型是字符串型,那么只要我们把变量声明为整数型不就可以运算了吗?使用declare命令就可以实现声明变量的类型。命令如下:
1 | [root@localhost ~]# declare [+/-][选项] 变量名 |
例子1:数值运算
那我们只要把变量声明为整数型不就可以运算了吗?试试吧:
1 | [root@localhost ~]# aa=11 |
这样运算好麻烦啊,没有办法啊,Shell在数值运算这里确实是比较麻烦,习惯就好了
例子2:数组变量类型
数组这个东东只有写一些较为复杂的程序才会用到,大家可以先不用着急学习数组,当有需要的时候再回来详细学习。那么数组是什么呢?所谓数组,就是相同数据类型的元素按一定顺序排列的集合,就是把有限个类型相同的变量用一个名字命名,然后用编号区分他们的变量的集合,这个名字称为数组名,编号称为下标。组成数组的各个变量成为数组的分量,也称为数组的元素,有时也称为下标变量。
一看定义就一头雾水,更加不明白数组是什么了。那么换个说法,变量和数组都是用来保存数据的,只是变量只能赋予一个数据值,一旦重复复制,后一个值就会覆盖前一个值。而数组是可以赋予一组相同类型的数据值。大家可以把变量想象成一个小办公室,这个办公室只能容纳一个人办公,办公室名就是变量名。而数组是一个大办公室,可以容纳很多人同时办公,在这个大办公室办公的每个人是通过不同的座位号来区分的,这个座位号就是数组的下标,而大办公室的名字就是数组名。
还是举个例子吧:
1 | [root@localhost ~]# name[0]="name0" |
注意数组的下标是从0开始的,在调用数组值时,需要使用${数组[下标]}的方式来读取。
不过好像在刚刚的例子中,我们并没有把name变量声明为数组型啊,其实只要我们在定义变量时采用了“变量名[下标]”的格式,这个变量就会被系统认为是数组型了,不用强制声明
例子3:环境变量
我们其实也可以使用declare命令把变量声明为环境变量,和export命令的作用是一样的:
1 | [root@localhost ~]# declare -x test=123 |
例子4:只读属性
注意一旦给变量设定了只读属性,那么这个变量既不能修改变量的值,也不能删除变量,甚至不能使用“+r”选项取消只读属性。命令如下:
1 | [root@localhost ~]# declare -r test |
不过还好这个变量只是命令行声明的,所以只要重新登录或重启,这个变量就会消失了。
例子5:查询变量属性和取消变量属性
变量属性的查询使用“-p”选项,变量属性的取消使用“+”选项。命令如下:
1 | [root@localhost ~]# declare -p cc |
- 使用expr或let数值运算工具
要想进行数值运算的第二种方法是使用expr命令,这种命令就没有declare命令复杂了。命令如下
1 | [root@localhost ~]# aa=11 |
使用expr命令进行运算时,要注意“+”号左右两侧必须有空格,否则运算不执行。至于let命令和expr命令基本类似,都是Linux中的运算命令,命令格式如下:
1 | [root@localhost ~]# aa=11 |
expr命令和let命令大家可以按照习惯使用,不过let命令对格式要求要比expr命令宽松,所以推荐使用let命令进行数值运算。
- 使用“$((运算式))”或“$[运算式]”方式运算
其实这是一种方式“$(())”和“$[]”这两种括号按照个人习惯使用即可。命令如下:
1 | [root@localhost ~]# aa=11 |
这三种数值运算方式,大家可以按照自己的习惯来进行使用。不过我们推荐使用“$((运算式))”的方式
2)、 Shell常用运算符
优先级 | 运算符 | 说明 |
---|---|---|
13 | -, + | 单目负、单目正 |
12 | !, ~ | 逻辑非、按位取反或补码 |
11 | * , / , % | 乘、除、取模 |
10 | +, - | 加、减 |
9 | << , >> | 按位左移、按位右移 |
8 | < =, > =, < , > | 小于或等于、大于或等于、小于、大于 |
7 | == , != | 等于、不等于 |
6 | & | 按位与 |
5 | ^ | 按位异或 |
4 | | | 按位或 |
3 | && | 逻辑与 |
2 | || | 逻辑或 |
1 | =,+=,-=,*=,/=,%=,&=, ^=,|=, <<=, >>= | 赋值、运算且赋值 |
运算符优先级表明在每个表达式或子表达式中哪一个运算对象首先被求值,数值越大优先级越高,具有较高优先级级别的运算符先于较低级别的运算符进行求值运算。
例子1:加减乘除
1 | [root@localhost ~]# aa=$(( (11+3)*3/2 )) |
例子2:取模运算
1 | [root@localhost ~]# bb=$(( 14%3 )) |
例子3:逻辑与
1 | [root@localhost ~]# cc=$(( 1 && 0 )) |
9、变量的测试与内容置换
变量置换方式 | 变量y没有设置 | 变量y为空值 | 变量y设置值 |
---|---|---|---|
x=${y-新值} | x=新值 | x为空 | x=$y |
x=${y:-新值} | x=新值 | x=新值 | x=$y |
x=${y+新值} | x为空 | x=新值 | x=新值 |
x=${y:+新值} | x为空 | x为空 | x=新值 |
x=${y=新值} | x=新值 y=新值 | x为空 y值不变 | x=$y y值不变 |
x=${y:=新值} | x=新值 y=新值 | x=新值 y=新值 | x=$y y值不变 |
x=${y?新值} | 新值输出到标准错误输出(就是屏幕) | x为空 | x=$y |
x=${y:?新值} | 新值输出到标准错误输出 | 新值输出到标准错误输出 | x=$y |
如果大括号内没有“:”,则变量y是为空,还是没有设置,处理方法是不同的;如果大括号内有“:”,则变量y不论是为空,还是没有设置,处理方法是一样的。
如果大括号内是“-”或“+”,则在改变变量x值的时候,变量y是不改变的;如果大括号内是“=”,则在改变变量x值的同时,变量y的值也会改变。
如果大括号内是“?”,则当变量y不存在或为空时,会把“新值”当成报错输出到屏幕上。
看的头都晕了吧,举几个例子说明下吧:
例子1
1 | [root@localhost ~]# unset y |
这是变量y不存在的情况,那如果变量y的值是空呢?
1 | [root@localhost ~]# y="" |
那如果变量y有值呢?
1 | [root@localhost ~]# y=old |
例子2:
那如果大括号内是“=”号,又该是什么情况呢?先测试下变量y没有设置的情况:
1 | [root@localhost ~]# unset y |
一旦使用“=”号,那么变量y和变量x都会同时进行处理,而不像例子1中只改变变量x的值。那如果变量y为空又是什么情况呢?
1 | [root@localhost ~]# y="" |
一旦在大括号中使用“:”,那么变量y为空或者不设定,处理方式都是一样的了。那如果y已经赋值了,又是什么情况:
1 | [root@localhost ~]# y=old |
例子3:
再测试下大括号中是“?”的情况吧:
1 | [root@localhost ~]# unset y |
那如果变量y已经赋值了呢:
1 | [root@localhost ~]# y=old |
五、环境变量配置文件
1、source命令
1 | [root@localhost ~]# source 配置文件 |
2、环境变量配置文件
1)、登录时生效的环境变量配置文件在Linux系统登录时主要生效的环境变量配置文件有以下五个:
- /etc/profile
- /etc/profile.d/*.sh
- ~/.bash_profile
- ~/.bashrc
- /etc/bashrc
环境变量配置文件调用过程
- 在用户登录过程先调用/etc/profile文件
在这个环境变量配置文件中会定义这些默认环境变量:
USER变量:根据登录的用户,给这个变量赋值(就是让USER变量的值是当前用户)。
LOGNAME变量:根据USER变量的值,给这个变量赋值。
MAIL变量:根据登录的用户,定义用户的邮箱为/var/spool/mail/用户名。
PATH变量:根据登录用户的UID是否为0,判断PATH变量是否包含/sbin、/usr/sbin和/usr/local/sbin这三个系统命令目录。
HOSTNAME变量:更加主机名,给这个变量赋值。
HISTSIZE变量:定义历史命令的保存条数。
umask:定义umask默认权限。注意/etc/profile文件中的umask权限是在“有用户登录过程(也就是输入了用户名和密码)”时才会生效。
调用/etc/profile.d/*.sh文件,也就是调用/etc/profile.d/目录下所有以.sh结尾的文件。
- 由/etc/profile文件调用/etc/profile.d/*.sh文件
这个目录中所有以.sh结尾的文件都会被/etc/profile文件调用,这里最常用的就是lang.sh文件,而这个文件又会调用/etc/sysconfig/i18n文件。/etc/sysconfig/i18n这个文件眼熟吗?就是我们前面讲过的默认语系配置文件啊。
- 由/etc/profile文件调用~/.bash_profile文件
~/.bash_profile文件就没有那么复杂了,这个文件主要实现了两个功能:
调用了~/.bashrc文件。
在PATH变量后面加入了“:$HOME/bin”这个目录。那也就是说,如果我们在自己的家目录中建立bin目录,然后把自己的脚本放入“~/bin”目录,就可以直接执行脚本,而不用通过目录执行了。
- 由
/.bash_profile文件调用/.bashrc文件
在~/.bashrc文件中主要实现了:
- 定义默认别名
- 调用/etc/bashr
- 由~/.bashrc调用了/etc/bashrc文件
在/etc/bashrc文件中主要定义了这些内容:
- PS1变量:也就是用户的提示符,如果我们想要永久修改提示符,就要在这个文件中修改
- umask:定义umask默认权限。这个文件中定义的umask是针对“没有登录过程(也就是不需要输入用户名和密码时,比如从一个终端切换到另一个终端,或进入子Shell)”时生效的。如果是“有用户登录过程”,则是/etc/profile文件中的umask生效。
- PATH变量:会给PATH变量追加值,当然也是在“没有登录过程”时才生效。
- 调用/etc/profile.d/.sh文件,这也是在“没有用户登录过程”是才调用。在“有用户登录过程”时,/etc/profile.d/.sh文件已经被/etc/profile文件调用过了。
这样这五个环境变量配置文件会被依次调用,那么如果是我们自己定义的环境变量应该放入哪个文件呢?如果你的修改是打算对所有用户生效的,那么可以放入/etc/profile环境变量配置文件;如果你的修改只是给自己使用的,那么可以放入/.bash_profile或/.bashrc这两个配置文件中的任一个。
可是如果我们误删除了这些环境变量,比如删除了/etc/bashrc文件,或删除了/.bashrc文件,那么这些文件中配置就会失效(/.bashrc文件会调用/etc/bashrc文件)。那么我们的提示符就会变成:
1 | -bash-4.1# |
2)、注销时生效的环境变量配置文件
在用户退出登录时,只会调用一个环境变量配置文件,就是~/.bash_logout。这个文件默认没有写入任何内容,可是如果我们希望再退出登录时执行一些操作,比如清除历史命令,备份某些数据,就可以把命令写入这个文件。
3)、其他配置文件
还有一些环节变量配置文件,最常见的就是~/bash_history文件,也就是历史命令保存文件。这个文件已经讲过了,这里我们只是把它归入环境变量配置文件小节而已
3、Shell登录信息
1)、 /etc/issue
我们在登录tty1-tty6这六个本地终端时,会有几行的欢迎界面。这些欢迎信息是保存在哪里的?可以修改吗?当然可以修改,这些欢迎信息是保存在/etc/issue文件中,我们查看下这个文件:
1 | [root@localhost ~]# cat /etc/issue |
可以支持的转义符我们可以通过man agetty命令查询,在表中我们列出常见的转义符作用:
转义符 | 作用 |
---|---|
\d | 显示当前系统日期 |
\s | 显示操作系统名称 |
\l | 显示登录的终端号,这个比较常用。 |
\m | 显示硬件体系结构,如i386、i686等 |
\n | 显示主机名 |
\o | 显示域名 |
\r | 显示内核版本 |
\t | 显示当前系统时间 |
\u | 显示当前登录用户的序列号 |
2)、 /etc/issue.net /etc/issue是在本地终端登录是显示欢迎信息的,如果是远程登录(如ssh远程登录,或telnet远程登录)需要显示欢迎信息,则需要配置/etc/issue.net这个文件了。使用这个文件时由两点需要注意:
- 首先,在/etc/issue文件中支持的转义符,在/etc/issue.net文件中不能使用。
- 其次,ssh远程登录是否显示/etc/issue.net文件中的欢迎信息,是由ssh的配置文件决定的。
如果我们需要ssh远程登录可以查看/etc/issue.net的欢迎信息,那么首先需要修改ssh的配置文件/etc/ssh/sshd_config,加入如下内容:
1 | [root@localhost ~]# cat /etc/ssh/sshd_config |
这样在ssh远程登录时,也可以显示欢迎信息,只是不再可以识别“\d”和“\l”等信息了
3)、 /etc/motd
/etc/motd文件中也是显示欢迎信息的,这个文件和/etc/issue及/etc/issue.net文件的区别是:/etc/issue及/etc/issue.net是在用户登录之前显示欢迎信息,而/etc/motd是在用户输入用户名和密码,正确登录之后显示欢迎信息。在/etc/motd文件中的欢迎信息,不论是本地登录,还是远程登录都可以显示。
4、定义Bash快捷键
1 | [root@localhost ~]# stty -a |
那么这些快捷键可以更改吗?可以啊,只要执行:
1 | [root@localhost ~]# stty 关键字 快捷键 |