1.什么是Shell及其特点:
Shell是命令解释器,它接收应用程序或用户命令,然后调用操作系统内核。
Shell是一个功能强大的编程语言,易编写、易调试、灵活性强。
2.Shell类型查看及配置:
查看主机上有哪个shell:#cat /etc/shells
查看当前所用shell:#echo $SHELL
更改当前shell: #chsh /bin/sh
sh是bash的软链接:
[root@centos7 ~]#ll /bin/ |grep bash
-rwxr-xr-x. 1 root root 964608 Oct 31 2018 bash
lrwxrwxrwx. 1 root root 10 Jul 17 2019 bashbug -> bashbug-64
-rwxr-xr-x. 1 root root 6964 Oct 31 2018 bashbug-64
lrwxrwxrwx. 1 root root 4 Jul 17 2019 sh -> bash
3.Shell脚本:
(1)开头:#!/bin/bash
(2)启动shell及执行权限与否:
./*.sh等价于sh ./*.sh等价bash ./*.sh,脚本执行是在重新启动一个子shell中执行。./*.sh需要加x权限则$0生效,sh与bash有无x对$0生效。
source ./*.sh等价于. ./*.sh,脚本执行是在当前shell进程中执行,无需重新启动一个子shell。 $0则无效。
【./*.sh执行脚本需要脚本有执行权限,这由于本质是脚本需要自己执行,所以需要执行权限;
而其余的则不需要,这由于是本质是bash解释器帮你执行脚本,所以脚本本身不需要执行权限】
(3)多命令操作:可以一行一行的写,不需要分号隔离或可以用上&&。
4.Shell变量:
(1)系统变量:
[root@centos7 ~]#echo $HOME $PWD $USER $SHELL
/root /root root /bin/bash
(2)自定义变量:变量=值 【等号两边没有空格,这里的等号是赋值】
定义变量:a=10
查看值: echo $a
撤销变量:unset a
声明一个静态变量:readonly变量
【不能unset,但可以退出此session就撤销了。静态变量声明时需要赋值,否则声明后不可赋值
非静态变量,可以转化为静态变量:readonly 变量名】
(3)变量定义规则:
变量名称是由字母、数字和下划线组成,但是不能以数字开头;环境变量名建议用大写。
等号两侧不能有空格。
在bash中,变量默认类型都是字符串类型,无法直接进行数字运算。
变量的值若有空格,需要使用双引号或单引号括起来。
例子如下:
[root@centos7 ~]#4ab=123
bash: 4ab=123: command not found...
[root@centos7 ~]#
[root@centos7 ~]#_4ab=123
[root@centos7 ~]#echo $_4ab
123
[root@centos7 ~]#
[root@centos7 ~]#a =3
bash: a: command not found...
[root@centos7 ~]#a= 3
bash: 3: command not found...
[root@centos7 ~]#a=3
[root@centos7 ~]#echo $a
3
[root@centos7 ~]#
[root@centos7 ~]#b=3+8
[root@centos7 ~]#echo $b
3+8
[root@centos7 ~]#
[root@centos7 ~]#c=345 ad
bash: ad: command not found...
[root@centos7 ~]#c="345 ad"
[root@centos7 ~]#echo $c
345 ad
[root@centos7 ~]#
(4)可把变量提升为全局环境变量,可供其他shell程序使用:
export 变量名
【可以先声明再赋值或声明的同时赋值:export a或export a=100】
(5)特殊变量:
$n,n为数字,$0代表脚本名称,$1-$9表示第一个到第九个参数,十及以上的参数需要用大括号${10}表示。 $n参数之间是以空格为分隔符。
$#,获取所有输入参数的个数,常用于循环。
$*与$@,都是获取命令行中所有的参数,但$*把所有的参数看成一个整体;$@把每个参数区分对待。
$?,最后一次执行的命令返回状态。值为0,证明上一个命令执行正确;值为非0,证明上一个命令执行不正确。
5.运算符:
(1)基本语法:
一种:$((运算式))或$[运算式]。+、-、*、/、%对应加、减、乘、除、取余。例子:$(((2+3)*4))等价于$[(2+3)*4]
另一种:expr +、-、\*、/、%对应加、减、乘、除、取余。【expr运算符间要有空格】。例子:expr `expr 2 + 3` \* 4
【bc、expr、let可用于数值计算:bc可以用于整数或小数的计算,而expr与let只能用于整数的计算
输入:整数,let和expr都无法进行浮点运算,但是bc和awk可以。
输出:bc、expr可直接显示计算结果;let则丢弃计算结果,可通过传递结果到变量,取变量值获得计算结果。
例子:let a=3+4.4 echo $a
expr `expr 2 + 3` \* 4
echo 9+4.4|bc 或echo 9+4.4"|bc
】
6.条件判断:[ condition ] 或 [[ condition ]]
(1)基本语法:
[ condition ] 【注意condition前后要有空格,条件非空即为true,[ a ]返回true;[]返回false。】
condition中的条件操作:所判断的内容与条件符号之间要空格。例子:a=abc [ $a == abc ];若是写成了[ $a==abc ]这是恒为true,由于$a==abc相当于5==abc并不是比较判断而是直接非空。
(2)[ ]与[[ ]]的区别:
相同点:二者都可以进行数字比较判断或字符串比较判断。
不相同点:-n或-z方式判断变量是否为空时,[]形式,需要变量加上双引号,而[[ ]]则不需要。例子:[ -n "var"] 或 [[ -n var]]
-a(and与)或-o(or或)对多个条件进行连接时,[]形式把-a或-o放在[]中,而[[ ]]不能使用-a或-o进行多条件连接。 例子:[ 4 -gt 2 -a 4 -lt 5 ]
&&或||进行多条件连接时,[]形式把&&或||放在[]外边,而[[ ]]形式把&&或||放在[[]]里边。[ 4 -gt 2 ]&&[ 4 -lt 5 ]或[[ 4 -gt 2 && 4 -lt 5 ]]
使用符号"=~"匹配正则表达时,只能使用[[ ]]。例子:[[ $var =~ [0-9]{11} ]]
当使用">"或者"<"判断字符串的ASCII值大小时,如果使用[]则加上转义符\。例子:[ a \< b]
(3)常用判断条件:
数字比较判断:-lt(le)ss than)小于、 -gt(greater than)大于
-eq(equal)等于、 -le(less)小于
-le(less equal)小于等于、-ge(greater equal)大于等于
字符串判断:【尽量把变量或字符串加上双引号进行比较判断】
当进行字符串判断时,可以用[ condition ] 或[[ condition ]]进行判断,但[ -n "var" ]或[ -z "var" ]时都需要加上双引号;而[[ -n var ]]或[[ -z var ]]不需要加上双引号。
=或==都可以表示字符串相同判断。
!=是进行字符串不相同判断。
-n是字符串为非空则真,可以理解为nozero。
-z是字符串为空则真,可以理解为zero。
(4)文件测试判断:【用相当路径时,注意当前所处位置及文件的路径;建议用上绝对路径】
-e是文件或目录存在为真。例子:[ -e path ]
-f是文件存在为真。例子:[ -f file_path ]
-d是目录存在为真。例子:[ -d dir_path ]
-r -w -x分别是读写执行。
-s文件存在并且大小大于0为真。例子:[ -s file_path ]
7.单小括号( )、双小括号( )、单中括号[ ]、双中括号及大括号{ }:
小括号( ):
命令组:括号中的命令将会新开一个子shell顺序执行,所以括号中的变量不能够被脚本余下的部分使用。括号中多个命令之间用分号隔开,最后一个命令可以没有分号,各命令和括号之间不必有空格。
命令替换:等同于`cmd`,shell扫描一遍命令行,发现了$(cmd)结构,便将$(cmd)中的cmd执行一次,得到其标准输出,再将此输出放到原来命令。有些shell不支持,如tcsh。
初始化数组:如:array a1=(a b c d)。
双小括号(( )):
整数运算:例子:echo $((4+5))或echo $((16#5f))结果为95(16进位转十进制)。
重定义变量:a=4;((a++))可以a重定义为5。
双括号中的变量可以不使用$符号前缀。括号内支持多个表达式用逗号分开。例子:for((i=1;i<10;i++))。
单中括号[ ]:
条件判断: [ condition ]。例子:[ $a == abc ]
在一个array 结构的上下文中,中括号用来引用数组中每个元素的编号。例子:a[1]
双中括号[[ ]]:
条件判断,[[ ]] 结构比[ ]结构更加通用。
大括号{ }:
大括号扩展:(通配(globbing))将对大括号中的文件名做扩展。在大括号中,不允许有空白,除非这个空白被引用或转义。例子:mkdir {a,b}或mkdir {a...d}。
代码块,又被称为内部组,这个结构事实上创建了一个匿名函数 。与小括号中的命令不同,大括号内的命令不会新开一个子shell运行,即脚本余下部分仍可使用括号内变量。括号内的命令间用分号隔开,最后一个也必须有分号。{}的第一个命令和左括号之间必须要有一个空格。
【几种特殊的替换结构:${var:-string},${var:+string},${var:=string},${var:?string}】
${var:-string}:如果var为空或者未设定,返回string,var不变
${var:+string}:如果var有值,返回string,var不变
${var:=string}:如果var为空或者未设定,返回string,且var=word
${var:?string}:如果变量var为空或者未设定,返回string并退出shell,string没有值则输出:parameter null or not set,用于检测var是否被正常赋值。
${var#*pattern}:# 从左到右,删除字符串开头至第一次出现的pattern部分
${var##*pattern}:# 从左到右,删除字符串开头至最后出现pattern部分
${var%pattern*}:# 从右到左,删除字符串结尾至第一次出现pattern的部分
${var%%pattern*}:# 从右到左,删除字符串结尾至最后一次出现pattern的部分
${ }引用变量的高级用法:
(1)字符串处理:【只有在pattern中使用了通配符才能有最长最短的匹配,否则没有最长最短匹配之分,只有完整匹配。】
【下面的只是更改输出的内容,而var原值并未修改。】
var=abcdefgabcdefg
${var#*pattern} # 从左到右,删除字符串开头至第一次出现的pattern部分
${var##*pattern} # 从左到右,删除字符串开头至最后出现pattern部分
例子如下:
[root@centos7 /data/shell]#var=abcdefgabcdefg
[root@centos7 /data/shell]#echo ${var#d}
abcdefgabcdefg
[root@centos7 /data/shell]#echo ${var#*d}
efgabcdefg
[root@centos7 /data/shell]#echo ${var##*d}
efg
${var%pattern*} # 从右到左,删除字符串结尾至第一次出现pattern的部分
${var%%pattern*} # 从右到左,删除字符串结尾至最后一次出现pattern的部分
例子如下:
[root@centos7 /data/shell]#var=abcdefgabcdefg
[root@centos7 /data/shell]#echo ${var%d}
abcdefgabcdefg
[root@centos7 /data/shell]#echo ${var%d*}
abcdefgabc
[root@centos7 /data/shell]#echo ${var%%d*}
abc
${var/pattern/substr} # 查找var存储的字符串中,第一个被pattern匹配到的字符替换为substr
${var//pattern/substr} # 查找var存储的字符串中,所有被pattern匹配到的字符替换为substr
${var/#pattern/substr} # 查找var存储的字符串中,开头被pattern匹配到的字符替换为substr
${var/%pattern/substr} # 查找var存储的字符串中,结尾被pattern匹配到的字符替换为substr
例子如下:var=abcdefgabcdefg
[root@centos7 /data/shell]#var=abcdefgabcdefg
[root@centos7 /data/shell]#echo ${var/d/D}
abcDefgabcdefg
[root@centos7 /data/shell]#echo ${var//d/D}
abcDefgabcDefg
[root@centos7 /data/shell]#echo ${var/#a/A}
Abcdefgabcdefg
[root@centos7 /data/shell]#echo ${var/%g/G}
abcdefgabcdefG
${var/pattern/} # 查找var存储的字符串中,删除第一次被pattern匹配到的字符
${var//pattern/} # 查找var存储的字符串中,删除所有被pattern匹配到的字符
${var/#pattern/} # 查找var存储的字符串中,删除开头被pattern匹配到的字符
${var/%pattern/} # 查找var存储的字符串中,删除结尾被pattern匹配到的字符
例子如下:var=abcdefgabcdefg
[root@centos7 /data/shell]#echo ${var/d/}
abcefgabcdefg
[root@centos7 /data/shell]#echo ${var//d/}
abcefgabcefg
[root@centos7 /data/shell]#echo ${var/#a/}
bcdefgabcdefg
[root@centos7 /data/shell]#echo ${var/%g/}
abcdefgabcdef
${var^^} # 将var存储的字符串中的所有小写替换为大写
${var,,} # 将var存储的字符串中的所有大写替换为小写,注意是英文逗号
例子如下:
[root@centos7 /data/shell]#echo $var
abcdefgabcdefg
[root@centos7 /data/shell]#varR=${var^^}
[root@centos7 /data/shell]#echo $varR
ABCDEFGABCDEFG
[root@centos7 /data/shell]#echo ${varR,,}
abcdefgabcdefg
(2)字符串切片:【下面的只是更改输出的内容,而var原值并未修改。】
${#var} # 引用字符串的长度
[root@centos7 /data/shell]#var=abcde
[root@centos7 /data/shell]#echo $var
abcde
[root@centos7 /data/shell]#echo ${#var}
5
${var:offset} # 从左到右,引用字符串从第offset(不包括offset)个字符开始到最后的部分
[root@centos7 /data/shell]#echo $var
abcde
[root@centos7 /data/shell]#echo ${var:3}
de
${var:offset:number} # 从左到右,引用字符串从第offset(不包括offset)个字符开始,长度为number的部分
[root@centos7 /data/shell]#echo $var
abcde
[root@centos7 /data/shell]#echo ${var:1:2}
bc
${var: -length} # 取字符串最右侧length个字符,注意-length前有一个空格
[root@centos7 /data/shell]#echo $var
abcde
[root@centos7 /data/shell]#echo ${var:-3}
abcde
[root@centos7 /data/shell]#echo ${var: -3}
cde
[root@centos7 /data/shell]#echo ${var:}
-bash: ${var:}: bad substitution
[root@centos7 /data/shell]#echo ${var::}
[root@centos7 /data/shell]#echo ${var::5}
abcde
${var: -length:number} # 先从右到左取length个字符,在从前边得到的字符中取长度为number的部分,同样的注意length前的空格
[root@centos7 /data/shell]#echo $var
abcde
[root@centos7 /data/shell]#echo ${var: -3:2}
cd
字符串变量赋值:【下面只有=才会有可能更改var的值,其余的都不人更改var的值】
${var:-value} # var为空或未设置,则返回value;有值则返回var的值
${var:+value} # var为空或未设置,则返回空值;有值则返回value
${var:=value} # var为空或未设置,则返回value并赋值给value;有值则返回var的值
${var:?error_info} # var为空或未设置,则返回error_info的信息;有值则返回var的值
以${var:=value}为例:
[root@centos7 /data/shell]#var=old #有值
[root@centos7 /data/shell]#echo $var
old
[root@centos7 /data/shell]#echo ${var:=new}
old
[root@centos7 /data/shell]#unset var #未设置
[root@centos7 /data/shell]#echo $var
[root@centos7 /data/shell]#echo ${var:=new}
new
[root@centos7 /data/shell]#echo $var
new
[root@centos7 /data/shell]#var= #为空
[root@centos7 /data/shell]#echo $var
[root@centos7 /data/shell]#echo ${var:=new}
new
[root@centos7 /data/shell]#echo $var
new
(3)变量间接引用:
如果var1=var2,var2=value,直接用变量var1引用value,这叫做变量的间接引用。
方法一:eval tmpvar=\$$var1 ;echo ${tmpvar}
方法二:引用${!var1}
例子如下:
[root@centos7 /data/shell]#var=old
[root@centos7 /data/shell]#var1=var2
[root@centos7 /data/shell]#var2=abc
[root@centos7 /data/shell]#echo $var1
var2
[root@centos7 /data/shell]#echo $var2
abc
[root@centos7 /data/shell]#echo \$$var1
$var2
[root@centos7 /data/shell]#eval tmpvar=\$$var1;echo $tmpvar #方法一
abc
[root@centos7 /data/shell]#echo $!var1
var1
[root@centos7 /data/shell]#echo ${!var1} #方法二
abc
7.流程控制:
(1)if:
基本语法:【if、[、condition、]之间要有空格】
if [ conditon ];then
执行xx程序
fi
或者
if [ condition ]
then
执行xx程序
fi
(2)case:
基本语法:
case $变量 in
"value1")
执行xx程序
;;
"value2")
执行xxx程序
;;
*)
执行xxxx程序
;;
esac
1)case行尾必须为单词“in”,每一个模式匹配必须以右括号“)”结束。
2)双分号“;;”表示命令序列结束,相当于java中的break。
3)最后的“*”表示默认模式,相当于java中的default。
(3)for:
基本语法:
形式一:
for((初始值;循环控制条件;变量变化))
do
执行程序
done
形式二:
for 变量 in value1 value2 value3...
do
执行程序
done
【$*与$@,都是代表全部元素,当加上双引号后则不同:"$*"表示元素一次输出; "$@"表示元素一个一个地输出。
以数组为例子:
【当${var[*]}与${var[@]}不加双引号时,输出结果都为元素一个一个地输出。当加上双引号后则前者全部输出,后者一个一个输出】
var=(a abc d e f 5)
for i in "${var[*]}"
do
echo $i
done
#最终结果为a abc d e f 5
echo “-===========”
for i in "${var[@]}"
do
echo $i
done
#最终结果为 a
abc
d
e
f
5
(4)while:
基本语法:
while [ condition ];do
执行程序
done
或者
while [ condition ]
do
执行程序
done
例子如下:
sum=0
i=1
while [ $i -le 100 ]
do
sum=$[$sum+$i]
i=$[$i+1]
done
echo $sum
8.read读取控制台输入:
基本语法:
read (选项) (参数)
选项:
-p:指定读取时的提示符;
-t:指定读取值时等待的时间(秒);时间一过就消失
参数:
变量:指定读取值的变量名。
例子:
read -t 4 -p "please input something:" var;echo $var
9.函数:【函数也是命令,可以
或$()来引用 】
(1)系统函数:
basename:【别看是路径,其实是对字符串的操作】
basename [string/pathname][suffix]则是删除所有的前缀包括最后一个(‘/’)字符,然后将字符串显示出来。选项suffix为后缀,如果suffix被指定了,basename会将pathname或string中的suffix去掉。
Examples:
basename /usr/bin/sort -> "sort"
basename include/stdio.h .h -> "stdio"
basename -s .h include/stdio.h -> "stdio"
basename -a any/str1 any/str2 -> "str1" followed by "str2"
dirname:【别看是绝对路径,其实是对字符串的操作】
dirname 则是去掉最后一个非斜杠部分和尾部斜杠; 如果名称中不包含 ‘/’,则输出‘. ’(指工作目录)。
Examples:
dirname /usr/bin/ -> "/usr"
dirname dir1/str dir2/str -> "dir1" followed by "dir2"
dirname stdio.h -> "."
(2)自定义函数:
基本语法:
[function]funname()
{
Action #后面可以加上分号,也可以不加上分号
[return int] #int这个数字在0-255(包括0与255)
}
funname #调用函数
例子如下:
[root@centos7 /data/shell]#cat function.sh
#!/bin/bash
test()
{
var=abc;
echo $var
return 144
}
test
[root@centos7 /data/shell]#bash function.sh
abc
[root@centos7 /data/shell]#echo $?
144
【函数的()不可少;先声明函数,再调用函数,shell脚本是逐行运行的,不会像其它语言一样先编译。
函数的返回值只能通过$?系统变量获得,也可能通过return返回。如果不加,将以最后一条命令运行结果作为返回值。return后跟数值(0-255)
】
第二个例子:
[root@centos7 /data/shell]#cat func2.sh
#!/bin/bash
test()
{
sum=$[$1+$2]
echo $sum
}
read -p "请输入第一个数:" num1
read -p "请输入第二个数:" num2
echo "这两数的和:"`test $num1 $num2` #函数也是命令,也可以echo "这两数的和:"$(test $num1 $num2)
10.shell工具:
(1)tr:translate的简写,主要用于压缩重复字符,删除文件中的控制字符以及进行字符转换操作。
基本语法:tr [OPTION]... SET1 [SET2]
-s:squeeze-repleats压缩重复字符。例如压缩空格:echo "a b c e"|tr -s" ",结果为a b c e【压缩是把连续相同的压缩成一个】
-d: delete删除字符。例如:echo "aabcc"|tr -d "b",结果为aacc。
-t:truncate,将SET1中字符用SET2对应位置的字符进行替换,一般缺省为-t。例如:echo "a b c"|tr -t " " ":" ,结果为a:b:c。
也可以利用字符集合进行转换: echo abcd|tr -t [:lower:] [:upper:] ,其结果为ABCD(小写转换成大写)。
(2)cut:切割,从文件的每一行剪切字节、字符和字段并输出。【只能以指定数目的制表符进行切割,如空格,要确定空格的个数】
基本语法:cut [选项参数] filename
选项参数:-f为列号,提取第几列;
例如: -f 1(某列)或-f 2,3(某几列)戒-f 3-(数字后负号从第三列往后)或-f -3(数字前负号从第三列之前)
-d为分隔符,按照指定分隔符分隔列;默认分隔符为制表符
(3)sort:排序
基本语法:sort (选项)(参数)
选项:-t指定排序时所用的分隔符;
-k指定需要排序的列;
-n依照数值的大小排序;
-r以相反的顺序来排序;
参数:指定待排序的文件列表。
例子:sort -t : -nrk 2 xxx
(4)grep:用于查找文件里符合条件的字符串。
基本语法:grep [选项参数] "match_pattern" filename 【match_pattern外的双引号可无】
选项参数:-v 输出除之外的所有行,相反输出
-E=egrep 使用扩展正则表达式
-o 只输出文件中匹配到的部分
-n 输出包含匹配字符串的行数
-r 递归搜索
-i 忽略大小写
-e 多个匹配样式
-q 静默
在grep搜索结果中包括或者排除指定文件:
#只在目录中所有的.php和.html文件中递归搜索字符"main()"
grep "main()" . -r --include *.{php,html}
#在搜索结果中排除所有README文件
grep "main()" . -r --exclude "README"
#在搜索结果中排除filelist文件列表里的文件
grep "main()" . -r --exclude-from filelist
打印出匹配文本之前或者之后的行:
#显示匹配某个结果之后的3行,使用 -A 选项:seq 10 | grep "5" -A 3
#显示匹配某个结果之前的3行,使用 -B 选项:seq 10 | grep "5" -B 3
#显示匹配某个结果的前三行和后三行,使用 -C 选项:seq 10 | grep "5" -C 3
#如果匹配结果有多个,会用“--”作为各匹配结果之间的分隔符:echo -e "a\nb\nc\na\nb\nc" | grep a -A 1
(5)sed: 是一种流编辑器,一次处理一行内容。
基本语法:sed [选项参数] 'command' filename
选项参数:-n是静默输出;-e多个命令执行的时候;-i修改文件内容;-r扩展正则表达式。
命令功能:p是显示,一般与-n配合使用只显示匹配到的行。
a是新增,a的后面可以接字符串,在下一行出现;'2a str'或'/str/a str2'
d是删除;'/str/d或2d'
s是替换;'s/str1/str2/g'
(6)awk: 文本分析工具,把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行分析处理。
基本语法:awk [选项参数] 'pattern1{action1} pattern2{action2} ...' filename
选项参数:-F指定输入文件分隔符;-v赋值一个用户定义变量。
pattern: 表示AWK在数据中查找的内容,就是模式匹配。
action:在找到匹配的内容时,所执行的一系列命令。
例子如下:
awk -F: 'BEGIN{print "user===>""shell"} {print $1,$7} END{print "newuser","/bin/newshell"}' /etc/passwd
awk -F: '/^root/{print $0 " "NR,NF}' /etc/passwd 结果为:root:x:0:0:root:/root:/bin/bash 1 7
ifconfig ens33|awk '/netmask/{print $2}'打印ip,默认是以空格分隔符