(一)变量与字符串操作
(1)变量的输出
Myname=Jack
Echo Hi,${Myname}con...
输出:Hi,Jackcon但如果后面接的不是英数单词,不是底线就不必使用{}隔开。
对于输出还有一种仿照C语言的printf命令。
如:
HI=”Hello World”
Printf “%s\n” “$HI”
对于%q会把变量中的特殊字符,用\字符转义,
HI=”ABC 123 xyz”
Printf “%p” “$HI”
则会输出ABC\ 123\ xyz,即在空格符前面加上\
(2)取消与清空变量
取消变量:
Unset -v(变量名称) -p(函数名称) name
不同的参数代表要取消的是什么类型的变量。不加任何选项会先尝试取消变量,如果失败的话再试着取消与该变量名同名的函数。
清空变量:
例如:myname=”abc”
Myname=
这样就等于清空了变量,但变量还存在,两种方法的差别就是变量是否还存在。
(3)变量和引号
Name=”jack
Echo “Hi, I am $name” =>输出 Hi,I am jack
Echo ‘Hi,I am $name’ =>输出 Hi,I am $name
为什么仅仅是引号的区别输出是不同的呢,因为单引号的作用是形成一个所见即所得的字符串,不会进行任何变量替换的操作。在双引号中可以通过\来进行转义。
(4)变量的有效范围
变量一旦设定完毕后只在当前的shell中有效,无法影响其他shell环境的变量,一旦script文件执行完毕(该script执行是为目前的shell的子shell),回到该shell中变量不再有效。
例子:cd.sh
#! /bin/bash
Cd /usr/local
Pwd
该script执行时,欲切换到目标目录,执行完毕后路径不会改变,因为这是在子shell中执行的,执行完成后,子shell也随即结束,又回到了父shell中,因此工作环境不会改变。
那么,如何才能使它在当前目录中进行跳转呢?很简单,只要执行.cd.sh或者source cd.sh
(5)环境变量
输出变量
当子shell产生后,它会继承父shell的环境变量等条件,因此,只要使变量成为环境变量就能为子shell取用,编程环境变量可用export这个命令:
Test=”Hello world”
Export Test
然后再在子shell中执行echo $Test就可以访问父shell中的这个值了。
另外,export是bash的内置命令,用途是吧一个变量输出,变成环境变量,使后续的各种操作(包括子shell)皆可以提取该变量的内容。
直接执行export能够列出目前所有的环境变量。相似的,用”declare -x”这个命令也能达到和export相同的效果。
当制定了一个环境变量后想取消的话就跟取消变量一样,使用unset就可以了。
(6)Bash的内置变量
CDPATH——用于缩短键入的路径
Export CDPATH=”/tmp/b/c:/var/log”:$HOME
Mkdir -p /tmp/b/c/a
Cd a
这样的话执行cd a时,默认是由工作目录找a,如果找不到的话就由$CDPATH中去找,可以直接切换到这个目录。
FUNCNAME——函数执行期间,此变量内容即为函数的名称。
Function show_name()
{
Echo $FUNCNAME
}
就会输出show_name
IFS——定义字段分隔符。默认值为:空格,tab字符,换行字符。
例:
PL是密码文件/etc/passwd中的一行,现在要把该行的各个字段分析出来,如下ifs.sh
#! /bin/bash
PL=”root:x:0:0:root:/root:/bin/bash”
#重新定义IFS,要以”:”为分隔符
IFS=”:”
#j代表第几个栏数
j=0
#以循环分析各个字段
For i in $PL
do
j=$((j+1)) #j增加1
Echo 第$j个字段是$i
Done
执行结果:
第1个字段是root
.....
第7个字段是/bin/bash
RANDOM——随机函数,直接使用是伪随机的,因此使用前可以设定一个数作为随机种子,
RANDOM =$$ #使用shell的进程编号当做随机数种子
Echo $RANDOM
其实,linux核心提供了更具随机运算的机制,它通过虚拟文件/dev/urandom来运行,用法如下:
head -1 /dev/urandom |od -N 2|head -1 |awk ‘{print $2 *1}’
指令的意思:使用head读取urandom输出的一行位数据,通过管道交给od印出2bytes的内容,在通过管道由head取一行数据,最后由awk印出第二个字段(先乘以1)当做随机数。
SECONDS——当前BashShell的已执行时间(以秒为单位)
Echo $SECONDS
输出秒数。
TMOUT——如果TMOUT的值大于0,则bash会等待TMOUT秒后,自动结束目前的bash shell
TMOUT=3
$1~$n——位置参数,第一个参数为$1,如果n超过9的话要用{}括起来如${10}
$0代表执行程序的名称
$*——代表所有的位置参数,并且视为一个字符串。
例如:test.sh abc 123 xyz 则$*的内容字符串为”abc 123 xyz”
$@——代表各位置参数组成的串行。
例如:test.sh abc 123 xyz 则$@的内容为”abc”,”123”,”xyz”这三个字符串
$#——代表参数的个数
$?——代表上一个命令执行结束后的返回值,通常0代表成功,非0代表有误。
$$——代表目前bash shell的进程编号
$!——上一个后台程序的进程编号
(6)调整变量的属性
只读readonly用法
执行readonly或readonly -p显示目前只读属性的变量列表
Readonly -f 函数名称——设定函数式不可改
Readonly -a 数组变量——设定是只读的数组
其实用declare可以进行大多数的属性调整。具体根据参数来定。
别名
建立别名:
Alias ll=’ls -l --color=auto’
取消别名:
Alias ll=ll
或者
Unalias 别名
(7)数组的用法
建立数组的几种方法:
A[0]=1
A[1]=”hello world”
Echo ${A[1]}
或者可以一次性设定每个元素的值
B=(12 13 14)
Echo ${B[2]}
更可以指定个别元素的索引,
C=([3]=77 [1]=100 [5]=66)
Echo ${C[5]}
这样的话分别指定了第4,2,6个元素,当指定一部分的索引时其余系统会自动续接。
E=(123 [8]=188 266)
Echo ${E[9]}
取出数组的所有的元素
Echo ${B[@]}
结果会输出12 13 14
将@改成*一样可以取出所有的元素,这两者的区别是,${B[@]}得到的是4个以空白隔开的数字,但是${B[*]}得到一整个字符串“12 13 14”
取得数组元素的个数
Echo ${#B[@]},结果是3,表示数组有三个元素。
取消数组或者数组元素
比如取消A数组
Unset A
如果想要取消某个元素的话就是
Unset A[3]
这样就等于取消了第四个元素
(8)Here Document
利用这个可以设定变量,基本语法为:
命令<<标记
.............
.............
标记
这样会把命令和标记之间的内容,利用转向输入的方式交给该命令去处理。
例如:
Info=’hello world’
Em=’text.txt’
Cat >$Em<<HERE
$info
HERE
结果就能存成文件,内容为hello world
控制Here Document的格式
1.关闭变量替换的功能:在第一个Here上加上单引号,然后再中间的文本如果有变量替换如$num就不会进行变量替换,而是输出$num。这在嵌入代码或注释之类的很有用。
利用Here Document做多行注释
:<<Here
注释1
注释2
Here
这样就添加了多行注释。
利用Here Document,打包C或其他语言的原始码
例:create_prg.sh
Cat<<’EOF’>hello.c
#include<stdio.h>
Int mian()
{
Printf(“hello world\n”);
Return 0;
}
EOF
#编译hello.c产生执行文件
Gcc -o hello hello.c
#如果编译成功,就执行
If[$? -eq 0];then
Echo “执行hello”...
Echo ./hello
./hello
Else
Echo ‘编译错误:hello.c’
Fi
利用这个script夹带了一个hello.c程序的原始码,执行后会产生hello.c,然后会编译,如果可以编译则执行,这就是shell script携带攻击程序的原型。
(二)高级变量
(1)测试存在性及空值:
测试变量存在性的基本用法
R=${myname -’bash’}//如果变量myname不存在的话符合判断条件,则吧-后面的字符串当做整个变量扩展的结果,并将它回传,给R。加入myname的值存在的话,r的值就是原来的值。
R=${myname:-’bash’}//测试变量不存在或其值为空,则传回默认值,这个与上面的差别在于还会判断存在性
R=${myname:=默认值}//测试变量不存在或者其值为空,给变量设一个默认值
R=${myname:?错误信息}//测试变量不存在或者其值为空,提示错误信息
R=${myname:+’true’}//如果存在的话返回true,检测存在且非空。
(2)取字符串切片,字符串长度
切片方法有两种:
Substr=${myname:4}//表示从第5个字符开始,截取子字符串,至字符串结束
Dir=${myname:1:3}//表示由第2个字符开始,截取3个字符长度的子字符串
(3)取部分位置参数
命令行参数第一个参数用$1来表示,第二个用$2表示,依次类推,例如test.sh x y z这个命令中$1就代表x,$0代表命令本身。
${@:起点}//由起点开始,取得后面的所有参数。第0个位置参数是$0
${@:起点:个数}//由起点开始,取得指定个数的位置参数
(4)计算字符串的长度
Filename=”helloworld”
Echo ${#filename}
执行结果返回了字符串的长度,
这里总结一下:
${#变量名称}//计算字符串长度
${#数组[@]}//取得数组的元素个数
${#数组[*]}//同上
除了这个方法,还有一个计算字符创长度的方法,可以利用外部程序expr来做。
Str=’here you are’
Len=$(expr length “$str”)//length数expr的选项,用来指定要做计算字符串长度的操作
Len=$(expr “$str” : ‘.*’)//这里:后面的.*是一个代表任意多个字符的字符串样式,expr会根据此样式来对比“字符串”,等于是计算字符串的长度。
(5)变量扩展:对比样式
Filename=”/usr/sbin/ntpdate”
R=${filename#/*/}
对比的样式是/*/,它的意思是说:凡是一对斜线之间有字符串者,(空字符串也可以),对比符合。因为#表示的由前面取最短的,所以,对比到最短的字符串是/usr/,所以将它删除,然后传回剩下的字符串,并设置给r,结果为sbin/ntpdate
对比删除样式总结:
1:${ 变量#样式} #由前面对比,删最短的
2:${ 变量##样式} #由前面对比,删最长的
3:${ 变量%样式} #由后面对比,删最短的
4:${ 变量%%样式}#由后面对比,删最长的
5:${ 变量/样式/替换字符串}#替换第一个对比符合的字符串
6:${ 变量//样式/替换字符串}#替换全部对比符合的字符串
7:${ 变量/#样式/替换字符串}#同5,但由变量值开头对比
8:${ 变量/%样式/替换字符串}#同5,但由变量值末尾对比
9:${ 变量/样式/} #删除第一个符合样式的字符串
10:${ 变量//样式/} #删除所有符合样式的字符串
11:${ 变量/#样式/} #同9,但由变量值开头的对比
12:${ 变量/%样式/} #同9,但由变量值尾部的对比
取代或者删除部分字符串
只替换第一个找到的合适的字符串
语法:${ 变量/样式/替换的字符串}
Act=”mail:x:8:8”
R=${act/:/,}
执行结果:第一个替换成
Mail,x:8:8
替换全部对比符合的字符串
语法:${ 变量//样式/替换的字符串}
例子省略,和上面类似,就把所有的符合样式的替换成将要替换掉字符串。
对于要删除的要求来说,只要将后面的要提换成的字符串删掉。
(三)流程控制
If的完整语法
If 条件测试1:then
命令区域1
Elif 条件测试2:then
命令区域2
Else
命令区域3
Fi
例子:
#! /bin/Bash
If grep -q “rm” fn.sh;then
Echo “fjind rm command”
Else
Echo “not found”
Fi
在条件测试中,执行的命令是:grep -q “rm” fn.sh,它寻找fn.sh文件里是否有关键字rm,选项-q表示不显示,仅借助$?来传回执行结果。
使用Bash关键字[[ ]]组成的句子:[[判断式]]
比如说比较两个字符串
If[[ str>xyz ]]...这个符号的判断是的前面和后面都要有一个或多个空格。
或者使用test,这是个Bash的内置命令。
If test “str” \> “xyz” #大于符号>对于Bash来言是特殊字符,要用\来转义。
或者使用内置命令[],这个和test对的用法是相同的,两者可互相改写。
If [“str” \>”xyz”]
使用-a -o进行逻辑组合
[-r filename1 -a -x filename]//这是判断filename1是否为可读和可执行-a
[-r filename1 -o -x filename]//这是判断filename1是否为可读或者可执行-o
&&和||复用
这两个复用可以达到if-then-else的效果,列如:
[-n ${DEBUG:-}] && set -v || set +v
这段代码使用-n测试变量是否有设非空值,如果有,表示要进行排错,接着执行逻辑and的下一条命令,如果无措就执行or的那条。这也看做是一种隐形的if-then-else的用法。