1、shell 概述
1)、什么是 shell
你可以把 shell 理解为一个命令解释器,比如说你在命令行输入 cd 命令,linux 怎么知道你输入的 cd 命令是什么意思,所以这时候就需要 shell,它会把你输入的命令翻译成 linux 可以认识的命令,交给 linux 内核去执行,并把内核执行结果翻译成我们可以理解的语言展现给我们。
我们可以通过 cat /etc/shells
来查看 linux 支持的 shell
2、echo 命令
echo [选项][输出内容]
选项:
-e
:支持反斜线控制的字符转换
-n
:取消输出后行末的换行符号
[root@hepingfly 桌面]# echo -e "atb"
a b
小知识点:
echo 输出字符串中含有感叹号会报错,解决方法就是在感叹号后面加一个空格
[root@hepingfly hepingfly]# echo "aaaa!" 在后面直接写 ! 会报错
bash: !": event not found
# 解决方法:在感叹号后加一个空格即可解决
[root@hepingfly hepingfly]# echo "aaa! "
aaa!
3、脚本执行方法
[root@hepingfly hepingfly]# ll
总用量 8
-rwxr-xr-x. 1 root root 29 4月 28 22:02 hello.sh
drwxr-xr-x. 2 root root 4096 4月 17 23:59 test
[root@hepingfly hepingfly]# ./hello.sh 使用相对路径
hello shp
[root@hepingfly hepingfly]# /home/hepingfly/hello.sh 使用绝对路径
hello shp
[root@hepingfly hepingfly]# bash hello.sh 直接使用 bash 去执行
hello shp
直接使用 bash 命令去执行 shell 脚本,甚至都不需要这个脚本有执行权限。
4、Bash 的基本功能
1)、历史命令
history [选项] [历史命令保存文件]
选项:
-c
:清空历史命令
-w
:把缓存中的历史命令写入历史命令保存文件。如果不手工指定历史命令保存文件,则放入默认历史命令保存文件~/.bash_history
中
注:
我们使用 history 命令查看历史命令和~/.bash_history
文件中保存的历史命令是不同的。那是因为当前登录操作的命令并没有直接写入~/.bash_history
文件,而是保存在缓存中。需要等当前用户注销之后,缓存中的命令才会写入~/.bash_history
文件。如果我们需要把内存中的命令直接写入~/.bash_history
文件,而不等用户注销才写入,可以使用history -w
命令
设置历史命令保存条数:
/etc/profile 文件
HISTSIZE=1000 这个值可以调大
历史命令调用:
- 使用 『
!n
』 重复执行第 n 条历史命令 - 使用 『
!!
』 重复执行上一条命令
2)、输入输出重定向
① Bash 的标准输入输出
设备设备文件名文件描述符类型键盘/dev/stdin0标准输入显示器/dev/stdout1标准输出显示器/dev/stderr2标准错误输出
② 输出重定向
解释下什么叫输出重定向:
命令的输出本身是应该输出给标准输出设备的,也就是输出到显示器上,重定向就是把它的输出方向改变,让它不在输出到显示器上,而是让它输出到文件中,这就是输出重定向。
标准输出重定向:
[root@hepingfly hepingfly]# ll > abc
# 这样就会把 ll 的结果输出到 abc 这个文件中
标准错误输出重定向:
[root@hepingfly hepingfly]# lljfkdf 2>abc
# 上面我乱写一个命令,显然会输出错误信息,这时候我把标准错误输出重定向到 abc 文件中
# 你直接写 lljfkdf >abc 这样肯定是不行的,因为这是一条错误命令,但是你加一个 2,表示错误输出,就可以了
正确输出和错误输出同时保存:
[root@hepingfly hepingfly]# ll > abc 2>&1
[root@hepingfly hepingfly]# llfsdfdsfsd > abc 2>&1
# 上面的意思就是把正确命令和错误命令都输出到 abc 这个文件,这样写的好处就是不管你命令写的正不正确都会把结果输出到 abc 这个文件
# 解释下 ll > abc 2>&1 这个命令:
# ll > abc 表示把命令结果输出到 abc 这个文件, 2>&1 表示把错误输出结果输出到标准输出,前面又是把标准输出输出到 abc 这个文件,所以不就是把标准输出和标准错误输出都输出到 abc 这个文件了嘛,至于 & 起一个标识作用,如果你不写 & ,就是 2>1 这个就表示把错误输出结果输出到 1 这个文件中
3)、多命令顺序执行x
[root@hepingfly 桌面]# ll;date;cd /home/ 这三条命令会按照顺序执行,不管前面命令执行成功还是失败,后面的命令都会照常执行
[root@hepingfly home]# ls && echo yes 如果第一个命令正确执行了,我就输出一个 yes。如果第一个命令报错,第二个命令是不会执行的。
[root@hepingfly home]# lsfaa || echo no 如果第一个命令没有正确执行,我就输出一个 no。如果第一个命令正确执行,第二个命令是不会执行的
[root@hepingfly home]# ll && echo yes || echo no 这条命令的意思是,如果第一个命令正确执行,则输出 yes,否则输出 no
5、shell 特殊符号
[root@hepingfly home]# a=$(date) 系统命令的执行结果赋值给变量
[root@hepingfly home]# echo $a
2019年 05月 04日 星期六 21:18:46 CST
[root@hepingfly home]# b=$(ll /home/) 理论上只要命令有输出,就可以赋值给变量
[root@hepingfly home]# echo $b
6、变量命名规则
在定义变量时,需要遵守一些规则:
- 变量名称可以由字母、数字、下划线组成,但是不能以数字开头
- 在 Bash 中,变量的默认类型都是字符串型,如果要进行数值运算,则必须指定变量类型为数值型
- 变量用等号连接值,等号左右两侧不能有空格
- 比如你在 shell 中定义一个变量,可以这么写: name=shp 但是不能这么写: name = shp 这种写法是错误的 因为在 linux 中命令的格式是: 命令 空格 选项 空格 参数 你定义变量的时候加空格,它会把你的变量当成 linux 命令去解析,这样显然有问题
- 变量的值如果有空格,需要使用单引号或者双引号扩起来。其中双引号括起来的内容 "$" "" 和反引号都有特殊含义,而单引号括起来的内容都是普通字符
- 在变量的值中,可以使用 "" 转义符
- 如果需要增加变量的值,那么可以进行变量值的叠加。不过变量需要使用双引号引起来
- test=123 test="$test"456 echo $test # 结果是123456 # 其实很好理解,使用 $ 调用变量的值,然后和后面的字符串拼接起来
- 如果是要把命令的结果作为变量值赋予变量,则需要使用反引号或者 $() 把命令包起来
- [root@hepingfly home]# test=$(date) 把 date 命令的执行结果赋值给变量 [root@hepingfly home]# echo $test 2019年 05月 05日 星期日 21:14:28 CST
- 环境变量名建议大写,用于区分
7、变量的分类
- 用户自定义变量:这种变量是最常见的变量,由用户自己定义变量名和变量值
- 环境变量:这种变量主要保存的是和系统环境相关的数据。
- 位置参数变量:这种变量主要是用来向脚本当中传递参数或数据的,变量名不能自定义,变量作用是固定的
- 预定义变量:在 Bash 中已经定义好的变量,变量名不能自定义,变量作用也是固定的
8、用户自定义变量
[root@hepingfly 桌面]# name=shp 定义变量
[root@hepingfly 桌面]# echo $name 调用变量
shp
变量查看:
set [选项]
选项:
-u
:如果设定此选项,调用未声明变量时会报错
[root@hepingfly 桌面]# echo $qqq 在 shell 中调用一个不存在的变量,输出结果是空
[root@hepingfly 桌面]# qqq=""
[root@hepingfly 桌面]# echo $qqq 给变量赋一个空值,输出结果也是空
# 因此根据输出结果我们无法分辨变量时不存在还是空值
[root@hepingfly 桌面]# set -u
[root@hepingfly 桌面]# echo $bbb 执行完 set -u 后再输出一个不存在的变量,就会报错
bash: bbb: unbound variable
# 当然上面执行 set -u 是临时生效的,需要永久生效的话要写到配置文件中
注:
你直接敲 set 是可以看到所有的用户自定义变量和环境变量
小说明:
在 shell 中你直接使用 $ 去调用一个变量,如果这个变量不存在,不会报错,会返回空。例如
echo $aaa
会返回一个空
删除变量:
unset 变量名
总结一下:
增:
变量名=变量值
删:
unset 变量名
改:
变量名=变量值 会直接覆盖
查:
set 可以查看所有自定义的用户变量
调用变量:
$变量名
9、环境变量
环境变量设置:
export 变量名=变量值
[root@hepingfly 桌面]# export age=100 使用 export 声明的变量即是环境变量
环境变量删除:
unset 变量名
[root@hepingfly 桌面]# unset age 删除环境变量
环境变量查询:
env
[root@hepingfly 桌面]# export man=shp
[root@hepingfly 桌面]# env|grep man env 可以查看环境变量
man=shp
PATH 变量:
系统查找命令的路径
[root@hepingfly bin]# echo $PATH
/usr/lib64/qt-3.3/bin:/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin:/root/bin
PATH 变量的值是用 『:
』分割的路径,这些路径就是系统查找命令的路径。也就是说当我们输入一个程序名,如果没有写入路径,系统就会到 PATH 变量定义的路径去找是否有可以执行的程序。如果找到则执行,否则会报 “命令没有发现的错误”。
现在假如说我们有一个自己的脚本,我不想输入路径就直接运行,有什么方法?
方法一:
把你自己写的脚本放到环境变量的路径下,这样就可以直接执行了。例如,把脚本放到 /bin 目录下
方法二:
利用变量叠加去修改环境变量的值
[root@hepingfly hepingfly]# PATH="$PATH":/home/hepingfly/
[root@hepingfly hepingfly]# echo $PATH
/usr/lib64/qt-3.3/bin:/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin:/root/bin:/home/hepingfly/ # 发现 /home/hepingfly/ 这个路径就被加到环境变量中去了
PS1 变量:
命令提示符设置。PS1 变量是用来定义命令行提示符的,可以按照我们的需求来定义自己喜欢的提示符
[root@hepingfly hepingfly]# echo $PS1
[u@h W]$
[root@hepingfly hepingfly]# PS1='[u@t W]$' 修改 PS1 变量(PS1 变量的值要用单引号包含,因为单引号中所有的特殊字符都当成普通字符对待,前面说过)
[root@21:43:44 hepingfly]# 发现这里的提示符已经变了
d: 显示日期,格式为 "星期 月 日"
H: 显示完整的主机名
h: 显示简写的主机名
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 用户会显示提示符为 "#" 如果是普通用户会显示提示符为 "$"
10、位置参数变量
count.sh 脚本:
#!/bin/bash
a=$1 # 这里拿到命令行中第一个参数
b=$2 # 这里拿到命令行中的第二个参数
sum=$(($a+$b)) # 在 shell 当中如果想要进行数值运算,需要使用 $(()) 把你要运算的算式给括起来,它才知道这是数值运算, $() 是用来括系统命令的,你括起来之后它才知道这是系统命令,然后执行,把结果赋值给变量
echo $sum
echo $0 # 这个就是输出命令行本身
[root@hepingfly hepingfly]# ./count.sh 22 11
33
./count.sh
小贴士
在 shell 当中如果想要进行数值运算,需要使用$(())
把你要运算的算式给括起来,它才知道这是数值运算,$()
是用来括系统命令的,你括起来之后它才知道这是系统命令,然后执行,把结果赋值给变量。
param.sh 脚本:
#!/bin/bash
for i in "$*" # $* 是把所有参数当成一个整体
do
echo $i # 这里我有多少个参数,就会一把输出出来
done
echo "============"
for y in "$@" # $@ 是把参数区别对待
do
echo $y # 有多少个参数,循环多少次,依次输出出来
done
echo "============"
echo "$#" # 这里会输出所有参数的个数
[root@hepingfly hepingfly]# ./param.sh 22 33 44
22 33 44 # $* 把所有参数当成一个整体,所以 3 个参数一起输出出来了
============
22
33 # $@ 把每个参数区分对待,因此 3 个参数分别输出出来
44
============
3 # $# 输出参数的个数
11、预定义变量
[root@hepingfly 桌面]# fdfda 随便乱输入一个命令
bash: fdfda: command not found
[root@hepingfly 桌面]# echo $? 输出最后一次命令执行状态
127 # 非 0 表示命令未正确执行
[root@hepingfly 桌面]# ll
总用量 28
-rw-r--r--. 1 root root 25872 3月 28 22:28 mysql80-community-release-el6-2.noarch.rpm
[root@hepingfly 桌面]# echo $?
0 # 0 表示命令正确执行
12、接收键盘输入
read [选项] [变量名]
选项:
-p "提示信息"
:在等待 read 输入时,输出的提示信息
-t 秒数
: read 命令会一直等待用户输入,使用此选项可以指定等待的时间
-n 字符数
:read 命令接收到指定的字符数,就会执行
-s
: 隐藏输入的数据,适用于机密信息的输入
[root@hepingfly hepingfly]# read -p "please input num: " -t 10 num
please input num: 12
[root@hepingfly hepingfly]# echo $num
12
13、declare 声明变量类型
linux 中所有变量的默认类型都是字符串类型,我们需要把变量声明为整数类型才可以进行运算。使用 declare 命令就可以实现声明变量的类型。
declare [+/-] [选项] 变量名
选项:
-
:给变量设定类型属性
+
:取消变量的类型属性
-a
:将变量设定为数组类型
-i
:将变量声明为整数类型
-r
:将变量声明为只读变量。注意:一旦设定为只读变量,既不能修改变量的值,也不能删除变量,设置不能通过+r
取消只读属性。
-x
:将变量声明为环境变量
-p
:显示指定变量的被声明的类型
变量设定为整数类型:
[root@hepingfly hepingfly]# a=1
[root@hepingfly hepingfly]# b=2
[root@hepingfly hepingfly]# c=$a+$b 直接相加是两个字符串做拼接操作
[root@hepingfly hepingfly]# echo $c
1+2
[root@hepingfly hepingfly]# declare -i c=$a+$b 声明变量 c 为数值类型
[root@hepingfly hepingfly]# echo $c
3
变量设定为数值类型:
[root@hepingfly hepingfly]# declare -a name[0]="shp"
[root@hepingfly hepingfly]# declare -a name[1]="kimi"
[root@hepingfly hepingfly]# declare -a name[2]="durant"
[root@hepingfly hepingfly]# echo ${name[*]} 使用 ${name[*]} 获取数组中所有变量
shp kimi durant
[root@hepingfly hepingfly]# echo ${name[0]} 使用 ${name[0]} 获取单个变量的值
shp
注:
我们前面说过使用 export 变量名
使用 export 声明的变量都是环境变量,其实它本质上就是使用 declare -x 变量名
将变量声明成环境变量。因为使用 export 变量名
比较简单,使用 declare -x 变量名
比较不容易记,所以我们都是用 export 变量名
去声明一个环境变量。
14、数值运算
在 shell 中你如果要进行数值运算,推荐使用 $((运算式))
方式运算
[root@hepingfly 桌面]# a=2
[root@hepingfly 桌面]# b=3
[root@hepingfly 桌面]# echo $(($a+$b))
5
15、环境变量配置文件
1)、登录时生效的环境变量配置文件
在 Linux 系统登录时主要生效的环境变量配置文件有以下五个:
/etc/profile
etc/profile.d/*.sh
~/.bash_profile
~/.bashrc
/etc/bashrc
主要区别是 /etc 下的配置文件对所有用户都生效,home 目录下只对当前用户生效
环境变量配置文件调用过程:
/etc/profile --> ~/.bash_profile --> ~/.bashrc --> /etc/bashrc --> 命令提示符
在用户登录过程中,先调用/etc/profile
文件,这个环境变量配置文件中主要定义了,如:PATH
环境变量,HOSTNAME
变量,umask
等。
然后由/etc/profile
文件调用~/.bash_profile
文件,在这个文件中主要调用了~/.bashrc
文件和在PATH
变量后面加上$HOME/bin
这个目录,也就是说如果我们在自己的家目录下建立 bin 目录,然后把自己的脚本放入~/bin
目录,就可以直接执行脚本而不用通过目录执行了~/.bash_profile
文件调用~/.bashrc
文件,在这个文件中主要实现了定义别名,和调用/etc/bashrc
/etc/bashrc
文件实现了,定义 PS1 变量,也就是用户提示符, umask 值
注:
如果我们误删了这些环境变量,比如说我们删了 /etc/bashrc
文件,或者删除了 ~/.bashrc
文件(这个文件会调用 /etc/bashrc
文件),那么我们的提示符就会变成:
-bash-4.1#
# 因为 PS1 变量是在 /etc/bashrc 文件中定义的,这个文件被删了,或者这个文件没被调用那么 PS1 变量就不会被定义,提示符自然就变成简易的 bash 版本信息。解决方法就是,从别的地方拷贝一份配置文件过来
2)、注销时生效的环境变量配置文件
在用户退出登录时,只会调用一个环境变量配置文件,就是
~/.bash_logout
。这个文件默认没有写入任何内容,如果我们希望在退出登录时执行一些操作,就可以把命令写入这个文件。
3)、其他配置文件
最常见的就是
~/.bash_history
文件,历史命令保存文件
Tips :
/etc/motd 文件/etc/motd
文件是在用户正确输入用户名和密码,正确登录之后显示欢迎信息。在/etc/motd
文件中的欢迎信息,不论是本地登录还是远程登录都可以显示。