shell 编程
一、Shell 概述
1、什么是 Shell
2、shell 的分类
Shell 类别 | 易学性 | 可移植性 | 编辑性 | 快捷性 |
Bourne Shell (sh) | 容易 | 好 | 较差 | 较差 |
Korn Shell (ksh) | 较难 | 较好 | 好 | 较好 |
Bourne Again (Bash) | 难 | 较好 | 好 | 好 |
POSIX Shell (psh) | 较难 | 好 | 好 | 较好 |
C Shell (csh) | 较难 | 差 | 较好 | 较好 |
TC Shell (tcsh) | 难 | 差 | 好 | 好 |
我们可以通过/etc/shells 文件来查询 Linux 支持的 Shell。命令如下:
[root@localhost ~]# vi /etc/shells
/bin/sh
/bin/Bash
/sbin/nologin
/bin/tcsh
/bin/csh
二、Shell 脚本的执行方式
1、echo 命令
[root@localhost ~]# echo [选项] "[输出内容]"
选项:
-e: 支持反斜线控制的字符转换(具体参见表 11-2)
-n: 内容输出后不换行
在 echo 命令中如果使用了"-e"选项,则可以支持控制字符,如表 11-2 所示:
控制字符 | 作 用 |
\\ | 输出\本身 |
\a | 输出警告音 |
\b | 退格键,也就是向左删除键 |
\c | 取消输出行末的换行符。和"-n"选项一致 |
\e | ESCAPE 键 |
\f | 换页符 |
\n | 换行符 |
\r | 回车键 |
\t | 制表符,也就是 Tab 键 |
\v | 垂直制表符 |
\0nnn | 按照八进制 ASCII 码表输出字符。其中 0 为数字零,nnn 是三位八进制数 |
\xhh | 按照十六进制 ASCII 码表输出字符。其中 hh 是两位十六进制数 |
2、Shell 脚本的执行
主要有这样两种方法:
赋予执行权限,直接运行
[root@localhost sh]# chmod 755 hello.sh //#赋予执行权限
绝对路径
相对路径运行
通过 Bash 调用执行脚本,在路径下才能用
[root@localhost sh]# bash hello.sh
Mr. Shen Chao is the most honest man.
三、Bash 的基本功能
1、历史命令
1) 历史命令的查看
[root@localhost ~]# history [选项] [历史命令保存文件]
选项:
-c: 清空历史命令
-w:把缓存中的历史命令写入历史命令保存文件。
如果不手工指定历史命令保存文件,则放入默认历史命令保存文件~/.bash_history 中
[root@localhost ~]# vi /etc/profile
…省略部分输出…
HISTSIZE=1000
…省略部分输出…
2) 历史命令的调用
如果想要使用原先的历史命令有这样几种方法:
使用上、下箭头调用以前的历史命令
使用“!n”重复执行第 n 条历史命令
使用“!!”重复执行上一条命令
使用“!字串”重复执行最后一条以该字串开头的命令
使用“!$”重复上一条命令的最后一个参数
2、命令与文件的补全
3、命令别名
命令格式:
[root@localhost ~]# alias
#查询命令别名
[root@localhost ~]# alias 别名='原命令'
#设定命令别名
既然我们说别名的优先级比命令高,命令执行时的具体顺序是这样的:
1、 第一顺位执行用绝对路径或相对路径执行的命令。
2、 第二顺位执行别名。
3、 第三顺位执行 Bash 的内部命令。
4 、第四顺位执行按照$PATH 环境变量定义的目录查找顺序找到的第一个命令。
为了让这个别名永久生效,可以把别名写入环境变量配置文件“~/.bashrc”。命令如下:
[root@localhost ~]# vi /root/.bashrc
4、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 | 恢复屏幕输出。 |
5、输入输出重定向
1) Bash 的标准输入输出
设备 | 设备文件名 | 文件描述符 | 类型 |
键盘 | /dev/stdin | 0 | 标准输入 |
显示器 | /dev/stdout | 1 | 标准输出 |
显示器 | /dev/stderr | 2 | 标准错误输出 |
2) 输出重定向(1省略了)
类 型 | 符 号 | 作用 |
标准输出重定向 | 命令 > 文件 | 以覆盖的方式,把命令的正确输出输 出到指定的文件或设备当中。 |
命令 >> 文件 | 以追加的方式,把命令的正确输出输 出到指定的文件或设备当中。 | |
标准错误输出重定向 | 错误命令 2>文件 | 以覆盖的方式,把命令的错误输出输 出到指定的文件或设备当中。 |
错误命令 2>>文件 | 以追加的方式,把命令的错误输出输 出到指定的文件或设备当中。 | |
正确输出和错误输出同时保存 | 命令 > 文件 2>&1 | 以覆盖的方式,把正确输出和错误输 出都保存到同一个文件当中。 |
命令 >> 文件 2>&1 | 以追加的方式,把正确输出和错误输 出都保存到同一个文件当中。 | |
命令 &>文件 | 以覆盖的方式,把正确输出和错误输 出都保存到同一个文件当中。 | |
命令 &>>文件 | 以追加的方式,把正确输出和错误输 出都保存到同一个文件当中。 | |
命令>>文件1 2>>文件2 | 把正确的输出追加到文件 1 中,把错 误的输出追加到文件 2 中。 |
3) 输入重定向
[root@localhost ~]# wc [选项] [文件名]
选项:
-c 统计字节数
-w 统计单词数
-l 统计行数
6、多命令顺序执行
多命令执行符 | 格式 | 作 用 |
; | 命令 1 ;命令 2 | 多个命令顺序执行,命令之间没有任何逻辑联系 |
&& | 命令 1 && 命令 2 | 当命令 1 正确执行($?=0),则命令 2 才会执行 当命令 1 执行不正确($? ¹ 0),则命令 2 不会执行 |
|| | 命令 1 || 命令 2 | 当命令 1 执行不正确($? ¹ 0),则命令 2 才会执行 当命令 1 正确执行($?=0),则命令 2 不会执行 |
7、管道符
1)行提取命令 grep
[root@localhost ~]# grep [选项] "搜索内容" 文件名
选项:
-A 数字: 列出符合条件的行,并列出后续的 n 行
-B 数字: 列出符合条件的行,并列出前面的 n 行
-c: 统计找到的符合条件的字符串的次数
-i: 忽略大小写
-n: 输出行号
-v: 反向查找
2) find 和grep 的区别
find 命令是在系统当中搜索符合条件的文件名,如果需要模糊查询,使用通配符(通配符我们下一小节进行介绍)进行匹配,搜索时文件名是完全匹配。
注意:find 命令是可以通过-regex 选项识别正则表达式规则的
grep 命令是在文件当中搜索符合条件的字符串,如果需要模糊查询,使用正则表达式进行匹配,搜索时字符串是包含匹配。
8、通配符
通配符 | 作 用 |
? | 匹配一个任意字符 |
* | 匹配 0 个或任意多个任意字符,也就是可以匹配任何内容 |
[] | 匹配中括号中任意一个字符。例如:[abc]代表一定匹配一个字符,或 者是 a,或者是 b,或者是 c。 |
[-] | 匹配中括号中任意一个字符,-代表一个范围。例如:[a-z]代表匹配一 个小写字母。 |
[^] | 逻辑非,表示匹配不是中括号内的一个字符。例如:[^0-9]代表匹配一个不是数字的字符。 |
9、Bash 中其他特殊符号
符 号 | 作 用 |
'' | 单引号。所见即所得,在单引号中所有的特殊符号,如“$”和“`”(反引号)都没有特殊含义。 |
"" | 双引号。在双引号中特殊符号都没有特殊含义,但是“$”、“`”和“\” 是例外,拥有“调用变量的值”、“引用命令”和“转义符”的特殊含义。 |
`` | 反引号。用来引用系统命令,在 Bash 中会先执行它。和$() 作用一样,不过推荐使用$(),因为反引号非常容易看错。 |
$() | 和反引号作用一样,用来引用系统命令。 |
() | 用于一串命令执行时,()中的命令会在子 Shell 中运行 |
{} | 用于一串命令执行时,{}中的命令会在当前 Shell 中执行。也可以用于变 量变形与替换。 |
[] | 用于变量的测试。[ "$oper" == "/" ],括号两边内侧要有空格 |
# | 在 Shell 脚本中,#开头的行代表注释。 |
$ | 用于调用变量的值,如需要调用变量 name 的值时,需要用$name 的方式 得到变量的值。 |
\ | 转义符,跟在\之后的特殊符号将失去特殊含义,变为普通字符。如\$将 输出“$”符号,而不当做是变量引用。 |
知道了父 Shell 和子 Shell,我们接着解释小括号和大括号的区别。如果是用于一串命令的执行,那么小括号和大括号的主要区别在于:
()执行一串命令时,需要重新开一个子 shell 进行执行
{}执行一串命令时,是在当前 shell 执行;
()和{}都是把一串的命令放在括号里面,并且命令之间用;号隔开;
()最后一个命令可以不用分号;
{}最后一个命令要用分号;
{}的第一个命令和左括号之间必须要有一个空格;
()里的各命令不必和括号有空格;
()和{}括号里面的某个命令的重定向只影响该命令,但括号外的重定向则影响到括号里
的所有命令。
四、Bash 的变量和运算符
1、什么是变量
定义变量时的规则:
变量名称可以由字母、数字和下划线组成,但是不能以数字开头。如果变量名是“2name”
则是错误的。
在 Bash 中,变量的默认类型都是字符串型,如果要进行数值运算,则必须指定变量类型为
数值型。
变量用等号连接值,等号左右两侧不能有空格。test=123
变量的值如果有空格,需要使用单引号或双引号包括。如:“test="hello world!"”。其
中双引号括起来的内容“$”、“\”和反引号都拥有特殊含义;而单引号括起来的内容都是
普通字符。
在变量的值中,可以使用“\”转义符。
变量值的叠加,变量需要用双引号包含"$变量名"或用${变量名}包含变量名。
如果是把命令的结果作为变量值赋予变量,则需要使用反引号或$()包含命令。
环境变量名建议大写,便于区分。
[root@localhost ~]# test=123
[root@localhost ~]# test="$test"456
[root@localhost ~]# echo $test
123456
#叠加变量 test,变量值变成了 123456
2、变量的分类
用户自定义变量:这种变量是最常见的变量,由用户自由定义变量名和变量的值。
环境变量:这种变量中主要保存的是和系统操作环境相关的数据,比如当前登录用户,用户的
家目录,命令的提示符等。不是太好理解吧,那么大家还记得在 Windows 中,同一台电脑可
以有多个用户登录,而且每个用户都可以定义自己的桌面样式和分辨率,这些其实就是
Windows 的操作环境,可以当做是 Windows 的环境变量来理解。环境变量的变量名可以自由
定义,但是一般对系统起作用的环境变量的变量名是系统预先设定好的。
位置参数变量:这种变量主要是用来向脚本当中传递参数或数据的,变量名不能自定义,变量
作用是固定的。
预定义变量:是 Bash 中已经定义好的变量,变量名不能自定义,变量作用也是固定的。
3、用户自定义变量
1)变量定义
[root@localhost ~]# name="shen chao"
#定义变量 name
2)变量调用
[root@localhost ~]# echo $name
3)变量查看
直接使用 set 命令,会查询系统中所有的变量,包含用户自定义变量和环境变量
[root@localhost ~]# set
选项:
-u:调用未定义变量时会报错(默认无任何提示)set -u
-x: 在命令执行之前,会把命令先输出一次;set -x
4)变量删除
[root@localhost ~]# unset 变量名
4、环境变量
1)环境变量设置
[root@localhost ~]# export age="18"
#使用 export 声明的变量即是环境变量
[root@localhost ~]# declare -x test=123
#我们其实也可以使用 declare 命令把变量 test 声明为环境变量
2)环境变量删除
env 命令和 set 命令的区别是,set 命令可以查看所有变量,而 env 命令只能查看环境变量。
[root@localhost ~]# unset gender
[root@localhost ~]# env | grep gender
#删除环境变量 gender
3)系统默认环境变量
env 命令可以查询到所有的环境变量,可是还有一些变量虽然不是环境变量,却是和 Bash 操作接口
相关的变量,这些变量也对我们的 Bash 操作终端起到了重要的作用。这些变量就只能用 set 命令来
查看了。
[root@localhost ~]# env
...
[root@localhost ~]# set
...
PATH 变量:系统查找命令的路径
先查询下 PATH 环境变量的值:
[root@localhost ~]# echo $PATH
/usr/lib/qt-3.3/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
PATH 变量的值是用“:”分割的路径,这些路径就是系统查找命令的路径。也就是说当我们输入了
一个程序名,如果没有写入路径,系统就会到 PATH 变量定义的路径中去寻找,是否有可以执行的程
序。如果找到则执行,否则会报“命令没有发现”的错误。
我们把自己的脚本拷贝到 PATH 变量定义的路径中,我们自己写的脚本也可以不输入路径而直接运行
[root@localhost ~]# cp /root/sh/hello.sh /bin/
#拷贝 hello.sh 到/bin 目录
我们可以修改 PATH 变量的值,而不是把程序脚本复制到/bin/目录中,通过变量的叠加就可以实现
[root@localhost ~]# PATH="$PATH":/root/sh
#在变量 PATH 的后面,加入/root/sh 目录
[root@localhost ~]# echo $PATH
/usr/lib/qt-3.3/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin:/root/sh
注意:当然我们这样定义的 PATH 变量只是临时生效,一旦重启或注销就会消失,如果想要永久生效,
需要写入环境变量配置文件,我们在“环境变量配置文件”小节中再详细介绍。
PS1 变量:命令提示符设置
PS1 是用来定义命令行的提示符的,PS1 变量的值要用单引号包含,否则设置不生效。
LANG 语系变量
查询支持语系:
[root@localhost src]# locale -a | more
aa_DJ
aa_DJ.iso88591
…省略部分输出…
#查询支持的语系
[root@localhost src]# locale -a | wc -l
735
#统计一下有多少个吧
查询当前系统语系使用 locale 命令:
[root@localhost src]# locale
LANG=zh_CN.UTF-8
LC_CTYPE="zh_CN.UTF-8"
...
我们还要通过文件/etc/sysconfig/i18n 定义系统的默认语系,查看下这个文件的内容:
[root@localhost src]# cat /etc/sysconfig/i18n
LANG="zh_CN.UTF-8"
LANG 定义的语系只对当前系统生效,要想永久生效就要修改/etc/sysconfig/i18n 文件。
如果我们是在图形界面中,或者是使用远程连接工具(如 SecureCRT),只要正确设置了语系,那么是可以正确显示中文的。当然远程连接工具也要配置正确的语系环境,具体配置方式可以参考 Linux 系统安装章节。
那么如果是纯字符界面(本地终端 tty1-tty6)是不能显示中文的,因为 Linux 的纯字符界面时
不能显示中文这么复杂的编码的。如果我们非要在纯字符界面显示中文,那么只能安装中文插件,如
zhcon 等。
5、位置参数变量
位置参数变量 | 作 用 |
$n | n 为数字,$0 代表命令本身,$1-$9 代表第一到第九个参数,十以上 的参数需要用大括号包含,如${10}. |
$* | 这个变量代表命令行中所有的参数,$*把所有的参数看成一个整体 |
$@ | 这个变量也代表命令行中所有的参数,不过$@把每个参数区分对待 |
$# | 这个变量代表命令行中所有参数的个数 |
$*会把接收的所有参数当成一个整体对待,而$@则会区分对待接收到的所有参数。举个例子:
6、预定义变量
预定义变量 | 作 用 |
$? | 最后一次执行的命令的返回状态。如果这个变量的值为 0,证明上一个命令正确执行;如果这个变量的值为非 0(具体是哪个数,由命令自己来决定),则证明上一个命令执行不正确了。 |
$$ | 当前进程的进程号(PID) |
$! | 后台运行的最后一个进程的进程号(PID) |
7、接收键盘输入read
[root@localhost ~]# read [选项] [变量名]
选项:
-p “提示信息”: 在等待 read 输入时,输出提示信息
-t 秒数: read 命令会一直等待用户输入,使用此选项可以指定等待时间
-n 字符数: read 命令只接受指定的字符数,就会执行,使用“-n 1”选项只接收一个输入字符就会执行
-s: 隐藏输入的数据,适用于密码信息的输入
变量名:
变量名可以自定义,如果不指定变量名,会把输入保存在默认变量 REPLY;
如果只提供了一个变量名,则整个输入行赋予该变量;
如果提供了一个以上的变量名,则输入行分为若干字,一个接一个地赋予各个变量,而命令行上的最后一个变量取得剩余的所有字。
例子:
read -t 30 -p "Please input your name: " name
#提示“请输入姓名”并等待 30 秒,把用户的输入保存入变量name 中
还是写个例子来解释下 read 命令:
8、Shell的运算符
1) 数值运算的方法
那如果我需要进行数值运算,可以采用以下三种方法中的任意一种:
使用 declare 声明变量类型
[root@localhost ~]# declare [+/-][选项] 变量名
选项:
-: 给变量设定类型属性
+: 取消变量的类型属性
-a: 将变量声明为数组型
-i: 将变量声明为整数型(integer)
-r: 讲变量声明为只读变量(注意,一旦设置为只读变量,既不能修改变量的值,也不能删量,
甚至不能通过+r 取消只读属性)
-x: 将变量声明为环境变量
-p: 显示指定变量的被声明的类型
例子 1:数值运算
我们只要把变量声明为整数型不就可以运算了
[root@localhost ~]# aa=11
[root@localhost ~]# bb=22
#给变量 aa 和bb 赋值
[root@localhost ~]# declare -i cc=$aa+$bb
#声明变量 cc 的类型是整数型,它的值是aa 和 bb 的和
[root@localhost ~]# echo $cc
33
#这下终于可以相加了
例子 2:数组变量类型
数组:就是相同数据类型的元素按一定顺序排列的集合
数组名:就是把有限个类型相同的变量用一个名字命名
下标:然后用编号区分他们的变量的集合
下标变量:组成数组的各个变量成为数组的分量,也称为数组的元素。
还是举个例子吧:
[root@localhost ~]# name[0]="shen chao"
#数组中第一个变量是沈超(大办公室第一个办公桌坐最高大威猛帅气的人)
[root@localhost ~]# name[1]="li ming"
#数组第二个变量是李明(大办公室第二个办公桌坐头发锃亮的人)
[root@localhost ~]# name[2]="tong gang"
#数组第三个变量是佟刚(大办公室第三个办公桌坐眼睛比超哥还小的老师)
[root@localhost ~]# echo ${name}
shen chao
#输出数组的内容,如果只写数组名,那么只会输出第一个下标变量
[root@localhost ~]# echo ${name[*]}
shen chao li ming tong gang
#输出数组所有的内容
注意:数组的下标是从 0 开始的,在调用数组值时,需要使用${数组[下标]}的方式来读取。
采用了“变量名[下标]”的格式,这个变量就会被系统认为是数组型了,不用强制声明。
例子 3: 环境变量
我们其实也可以使用 declare 命令把变量声明为环境变量,和 export 命令的作用是一样的:
[root@localhost ~]# declare -x test=123
#把变量 test 声明为环境变量
例子 4:只读属性
注意一旦给变量设定了只读属性,那么这个变量既不能修改变量的值,也不能删除变量,甚至不能
使用“+r”选项取消只读属性。
不过还好这个变量只是命令行声明的,所以只要重新登录或重启,这个变量就会消失了。
例子 5:查询变量属性和取消变量属性
变量属性的查询使用“-p”选项,变量属性的取消使用“+”选项。命令如下:
[root@localhost ~]# declare -p cc
[root@localhost ~]# declare +x test
四则运算器脚本
#使用“-n 1”选项只接收一个输入字符就会执行(都不用输入回车)
//没有判断num1和num2是不是纯数字
使用 expr 数值运算工具
数值运算的第二种方法是使用 expr 命令,这种命令就没有 declare 命令复杂了。命令如下:
[root@localhost ~]# aa=11
[root@localhost ~]# bb=22
#给变量 aa 和变量bb 赋值
[root@localhost ~]# dd=$(expr $aa + $bb)
#dd 的值是 aa 和 bb 的和。注意“+”号左右两侧必须有空格
[root@localhost ~]# echo $dd
33
使用 expr 命令进行运算时,要注意“+”号左右两侧必须有空格,否则运算不执行。
使用let 数值运算工具
数值运算的第三种方法是使用 let 命令,命令格式如下:
[root@localhost ~]# aa=11
[root@localhost ~]# bb=22
#给变量 aa 和变量bb 赋值
[root@localhost~]# let ee=$aa+$bb
[root@localhost~]# echo $ee
33
#变量 ee 的值是aa 和 bb 的和
[root@localhost ~]# n=20
#定义变量n
[root@localhost ~]# let n+=1
#变量n 的值等于变量本身再加 1
[root@localhost ~]# echo $n
21
let 命令对格式要求要比 expr 命令宽松,所以推荐使用 let 命令进行数值运算。
使用“$((运算式))”或“$[运算式]”方式运算
其实这是一种方式“$(())”和“$[]”这两种括号按照个人习惯使用即可。命令如下:
[root@localhost ~]# aa=11
[root@localhost ~]# bb=22
[root@localhost ~]# ff=$(( $aa+$bb ))
[root@localhost ~]# echo $ff
33
#变量 ff 的值是aa 和 bb 的和
[root@localhost ~]# gg=$[ $aa+$bb ]
[root@localhost ~]# echo $gg
33
#变量 gg 的值是aa 和 bb 的和
总结:5种数值运算方法:
1)declare -i cc=$aa+$bb
2)cc=$(expr $aa+$bb)
3)let cc=$aa+$bb
4)cc=$(( $aa+$bb )) 推荐
5)cc=$[ $aa+$bb ]
这三种数值运算方式,我们推荐使用“$((运算式))”
2)Shell 常用运算符
优先级 | 运算符 | 说明 |
13 | -, + | 单目负、单目正 |
12 | !, ~ | 逻辑非、按位取反或补码 |
11 | * , / , % | 乘、除、取模 |
10 | +, - | 加、减 |
9 | > | 按位左移、按位右移 |
8 | =, < , > | 小于或等于、大于或等于、小于、大于 |
7 | == , != | 等于、不等于 |
6 | & | 按位与 |
5 | ^ | 按位异或 |
4 | | | 按位或 |
3 | && | 逻辑与 |
2 | || | 逻辑或 |
1 | =,+=,-=,*=,/=,%=,&=, ^=, |=, >= | 赋值、运算且赋值 |
运算符优先级表明在每个表达式或子表达式中哪一个运算对象首先被求值,数值越大优先级越高,具有较高优先级级别的运算符先于较低级别的运算符进行求值运算。
例子 1: 加减乘除
[root@localhost ~]# aa=$(( (11+3)*3/2 ))
#虽然乘和除的优先级高于加,但是通过小括号可以调整运算优先级
[root@localhost ~]# echo $aa
21
例子 2:取模运算
[root@localhost ~]# bb=$(( 14%3 ))
[root@localhost ~]# echo $bb
2
#14 不能被 3 整除,余数是 2
例子 3:逻辑与
[root@localhost ~]# cc=$(( 1 && 0 ))
[root@localhost ~]# echo $cc
0
#逻辑与运算只有想与的两边都是 1,与的结果才是 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:
///变量 y 没有设置的情况
[root@localhost ~]# unset y
#删除变量y
[root@localhost ~]# x=${y-new}
#进行测试
[root@localhost ~]# echo $x
new
#因为变量y 不存在,所以 x=new
[root@localhost ~]# echo $y
#但是变量y 还是不存在的
///变量 y 的值是空
[root@localhost ~]# y=""
#给变量y 赋值为空
[root@localhost ~]# x=${y-new}
#进行测试
[root@localhost ~]# echo $x
[root@localhost ~]# echo $y
#变量x 和变量y 值都是空
///变量 y 有值
[root@localhost ~]# y=old
#给变量y 赋值
[root@localhost ~]# x=${y-new}
#进行测试
[root@localhost ~]# echo $x
old
[root@localhost ~]# echo $y
old
#变量x 和变量y 的值都是 old
五、环境变量配置文件
1、source 命令
[root@localhost ~]# source 配置文件 //刷新当前的shell环境,让修改生效
或
[root@localhost ~]# . 配置文件
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/profile 文件调用~/.bash_profile 文件
~/.bash_profile 文件就没有那么复杂了,这个文件主要实现了两个功能:
调用了~/.bashrc 文件。
在 PATH 变量后面加入了“:$HOME/bin”这个目录。那也就是说,如果我们在自己的家目录中建立
bin 目录,然后把自己的脚本放入“~/bin”目录,就可以直接执行脚本,而不用通过目录执行了。
由~/.bash_profile 文件调用~/.bashrc 文件
在~/.bashrc 文件中主要实现了:
定义默认别名,所以超哥把自己定义的别名也放入了这个文件。
调用/etc/bashrc
由~/.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 文件)。那么我们的提示符就会变
成:
-bash-4.1#
3、Shell 登录信息
1) /etc/issue
我们在登录tty1-tty6 这六个本地终端时,会有几行的欢迎界面。这些欢迎信息是保存在/etc/issue 文件中,我们查看下这个文件:
可以支持的转义符我们可以通过 man agetty 命令查询,在表中我们列出常见的转义符作用:
转义符 | 作 用 |
\d | 显示当前系统日期 |
\s | 显示操作系统名称 |
\l | 显示登录的终端号,这个比较常用。 |
\m | 显示硬件体系结构,如 i386、i686 等 |
\n | 显示主机名 |
\o | 显示域名 |
\r | 显示内核版本 |
\t | 显示当前系统时间 |
\u | 显示当前登录用户的序列号 |
2) /etc/issue.net
远程登录(如 ssh 远程登录,或 telnet远程登录)显示欢迎信息,则需要配置/etc/issue.net 这个文件了。使用这个文件时由两点需要
注意:
首先,在/etc/issue 文件中支持的转义符,在/etc/issue.net 文件中不能使用。
其次,ssh 远程登录是否显示/etc/issue.net 文件中的欢迎信息,是由 ssh 的配置文件决定的。
如果我们需要 ssh 远程登录可以查看/etc/issue.net 的欢迎信息,那么首先需要修改 ssh 的配置
文件/etc/ssh/sshd_config,加入如下内容:
[root@localhost ~]# cat /etc/ssh/sshd_config
…省略部分输出…
# no default banner path
#Banner none
Banner /etc/issue.net
…省略部分输出…
这样在 ssh 远程登录时,也可以显示欢迎信息,只是不再可以识别“\d”和“\l”等信息了
3) /etc/motd
/etc/motd 文件中也是显示欢迎信息的,这个文件和/etc/issue 及/etc/issue.net 文件的区别是:
/etc/issue 及/etc/issue.net 是在用户登录之前显示欢迎信息,而/etc/motd 是在用户输入用户名和
密码,正确登录之后显示欢迎信息。在/etc/motd 文件中的欢迎信息,不论是本地登录,还是远程登
录都可以显示。
4、定义 Bash 快捷键
[root@localhost ~]# stty -a
#查询所有的快捷键
定义 Bash 快捷:
[root@localhost ~]# stty 关键字 快捷键
例如:
[root@localhost ~]# stty intr ^p
#定义 ctrl+p 快捷键为强制终止,“^”字符只要手工输入即可
[root@localhost ~]# stty -a
speed 38400 baud; rows 21; columns 104; line = 0;
intr = ^P; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = ; eol2 = ; swtch
= ;
start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O; min =
1; time = 0;
#强制终止变成了 ctrl+p 快捷键