shell总结
shell脚本的本质是shell命令的有序集合
建立shell脚本的步骤:建立shell脚本,编写任意多行操作系统命令或shell命令,增加文件的执行权限,结束
shell变量
shell允许用户建立变量存储数据,但不支持数据类型。将任何赋给变量的值都解释为一串字符
shell有如下四种变量:用户自定义变量,位置变量,预定义变量,环境变量
用户自定义变量:
定义变量:COUNT=1
使用时前面加$:echo $COUNT
删除变量的赋值:unset COUNT
位置变量:
$0 与键入的命令行一样,包含脚本文件名
$1,$2...$9 分别包含第一个到第九个命令行参数
$# 包含命令行参数的个数
$@ 包含所有命令行参数:“$1,$2...$9 ”
$? 包含前一个命令的退出状态
$* 包含所有命令行参数:“$1,$2...$9 ”
$$ 包含正在执行进程的ID号
shell环境变量
CDPATH 用于cd命令的查找路径
HOME 用户主目录
PATH 路径
shell 程序和语句
shell程序由0到n条shell语句构成,shell语句包括三大类:功能性语句、结构性语句、说明性语句
说明性语句:以#开始的部分,不被解释执行
可以出现在程序的任意位置,可以单独一行,也可以接在执行语句的后面
功能性语句:任意操作系统命令、shell内部命令、自编程序、等
read 从标准输入读出一行,赋给后面的变量
read var #把读入的数据全部赋给var
read var1 var2 var3 #把读入一行的第一、二个词分别赋给var1、var2,其他的都赋给var3
如果执行read语句时标准输入无数据,则程序在此停留等候,直到数据到来或终止运行
expr 主要用于简单的整数运算,包括 + - \* / % 等
反撇号用于引用命令的运行结果
test 用于测试三种对象:字符串、整数、文件属性
可用[ ]代替,注意左右都至少一个空格
如:test “$answer” = “yes” #变量answer的值是否为字符串yes
test $num -eq 18 #变量num的值是否为整数18
test -d tmp #测试tmp是否为一个目录名
结构性语句:条件测试语句、多路分支语句、循环语句、循环控制语句、后台执行语句
条件测试语句
if...then...else...fi
语法结构:
if 表达式
then
命令表1 #一条或者若干条命令
else
命令表2 #一条或者若干条命令
fi
如果表达式为真,执行命令表1,否则执行命令表2
例子;
if [ -f S1 ] #测试参数是否为文件
then
echo “File $1 exists”
fi
if [-d $HOME/$1] #测试参数是否为目录
then
echo “File $1 is a directory”
fi
多路分支语句
case...esac
语法结构:
case 字符串变量 in #case语句只能检测字符串变量
模式1)
命令表1
;;
模式2)
命令表2
;;
。。。。
*) # *表示其他所有
命令表n
;;
esac
例如:
case $1 in
file1)
echo “file1”
;;
file2)
echo “file2”
;;
*)
echo “others”
;;
esac
循环语句
for...do...done
当循环次数已知或者确定时,使用for循环语句来多次执行一条或一组命令,循环体由do和done来限定
for 变量名 in 单词表
do
命令表
done
说明:变量依次取单词表中的各个单词,每取依次单词,就执行一次循环体,循环次数为单词表中的单词个数,命令表中可以是一条或由分号隔开的多条命令
如果单词表是命令行上的所有位置参数时,可以省去 in 单词表
list=`ls`
for file in $list
do
if[ $1 = $file ]
then
echo “$file found”;
exit; #退出shell脚本
fi
done
while...do...done
语法结构:
while 命令或表达式
do
命令表
done
说明:while首先测试其后的命令或表达式的值,如果为真,就执行一次循环体中的命令,然后再测试该命令或表达式的值,执行循环体,知道为假,退出循环
until...do...done
语法结构:
until 命令或表达式
do
命令表
done
与上面的相反
循环控制语句:
break 和 continue
break n 跳出n层
continue 马上跳转到最近一层循环的下一轮循环
continue n 转到最近n层循环语句的下一轮循环上
shell函数
shell程序中,常把完成固定功能且多次使用的一组命令封装在一个函数中,每当要使用时,调用函数名即可
函数调用前必须先定义,即顺序上先定义函数,再调用
调用程序可以传递参数给函数,函数可以用return语句把运行结果返回调用程序
函数只在当前shell中起作用,不能输出到子shell中
shell函数定义格式
function funtion_name () #function可以省掉
{
...
}
函数调用方式
value_name = `function_name [arg1 arg2 ...]` #函数结果返回给变量
或
function_name [arg1 arg2 ...]
echo $? #获取函数返回的状态
函数变量的作用域
全局作用域:在脚本的其他地方都可以访问该变量
局部作用域:只能在声明的作用域内访问
局部变量的声明: Local variable_name = value
脚本调试:
跟踪脚本执行结果:
在希望开始调试的地方插入 set -x
在希望结束调试的地方插入 set +x
---------------------------------------------------------------------
---------------------------------------------------------------------
Bash shell结构
1:shbang行:脚本的第一行,告之内核用哪个shell解释shell脚本,由#!加shell的完整路径组成
2:注释:#后面的为注释,可以在一行后
3:shell通配符或元字符:shell中字符意义比较特殊,如* ? [] > < 2> >> |等,防止这些字符被解释,则必须引用他们
4:局部变量:局部变量作用域在本shell中
5:全局变量:又称为环境变量,由内置的export命令创建,作用域在本shell及子shell中
6:提取变量值:$
7:参数:可以从命令行传递参数给脚本
8:命令替换:`A` $(A) 结果可以赋给一个变量或代替所在位置
---------------------------------------------------------------------
正则表达式
正则表达式是一种字符模式,在查找过程中匹配指定的字符,可以用特殊的元字符来控制它们,正则表达式都被置于两个正斜杠//之间
元字符:表达的是不同于字符本身的含义
本书中的元字符有两类:shell元字符、正则表达式元字符,它们各司其职,shell元字符是由shell
解析的,就是下面所讲的文件名置换;正则表达式元字符是由各种执行模式操作的程序来解析的,如vi、grep、sed、awk
---------------------------------------------------------------------
正则表达式元字符:
^ 行首定位
$ 行尾定位
. 匹配单个字符
* 匹配0或多个重复的位于*前的字符
[] 匹配指定组字符中的任意一个 ;如[LlT]
[-] 匹配指定范围内的字符 ;如[x-yA-Z0-8]
[^] 匹配不在指定组内的字符
[^ - ]跟上面的相反
\ 转移跟在后面的字符 #转义元字符,使之不被解释
\< 词首定位符 #定位以什么开头的词
\> 词尾定位符 #定位以什么结尾的词
---------------------------------------------------------------------
grep 家族
grep家族由grep、egrep、fgrep组成
grep命令在文件中全局查找指定的正则表达式,并打印所有包含该表达式的行
一般格式:grep [选项] 基本正则表达式 [文件]
选项:-n 显示行号 -i 大小写不敏感 -w表达式作为词来查找,也就是不是一个词的一部分 -r 递归查找
基本正则表达式:可为字符串,如果为字符串,最好用“”如果是模式匹配,用‘’调用变量时,也应该使用“”
文件:可以为多个文件;如 A1 A2
常用举例子
grep -n “your” www #文件www中查找含有your单词的行,且输出行号
grep -nw “your” www #文件www中查找含以your做单词的行,且输出行号
grep -nr ‘[a-zA-Z0-9].you’ ./ #递归./ 中查找含有以a-z A-Z 0-9开始的单词的行,且输出行号
---------------------------------------------------------------------
find命令及xargs
find pathname -options [-print -exec -ok]
常用的options为name 此时记住要用引号将文件名模式引起来
find ./ “*org.txt” #在当前目录及子目录中寻找以org.txt结尾的文件
find 找到文件后可用xargs对其操作
find ./ “*org.txt” | xargs ls
find ./ “*org.txt” | xargs grep “device” #在结果中搜索device
---------------------------------------------------------------------
启动
系统启动后
->init->getty进程
->/bin/login 初始化环境,启动shell
->/bin/bash 执行/ect/profile,执行~/.bash_profile ~/.bash_login ~/.profile,执行
~/.bashrc
->等待用户输入
---------------------------------------------------------------------
环境
一个进程的环境包括:变量等,它定义了可以从一个进程继承到下一个进程的特性
用户的shell配置定义在shell初始化文件中,bash shell有许多启动文件,这些文件可以执行source命令,对一个文件执行source命令
会使得这个文件中的所有设置称为当前shell的一部分,也就是说不会创建子shell
登陆时,会执行~/.bash_profile文件执行source命令,如无,则source ~/.bash_login,若无,则
source ~/.profile,这三个文件只能source一个,再source ~/.bashrc
~/.bashrc:包含特定的变量和别名,当一个新的bash shell启动或bash脚本启动时会自动执行source ~/.bashrc
在当前提示符下输入shell或bash启动的是子shell
/etc/bashrc:系统级的函数和别名可以在/etc/bashrc文件中设置,主提示符一般在这设置
~/.profile:是一个用户定义的初始化文件,它是被Bourne shell使用的,因此不能包括对bash shell的特定设置,运行bash
时只有没找到其他文件时才source此文件,它允许用户定制和修改shell环境,也可以放应用程序的初始化
---------------------------------------------------------------------
source命令或dot命令(.) 和 ./命令
source命令式内置的bash命令,来自C shell
dot命令也就是. 来自Bourne shell
二者完全一样,都是一个脚本名作为参数,shell将在当前的shell环境中执行这个脚本,也就是不启动子shell,脚本中的设置的所有参数将成为当前shell
环境的一部分。
./执行脚本时是创建子shell,脚本中的设置参数在脚本退出后就无效了。
例子:在家目录下的.bashrc中加入WANG=”ni hao”
然后. .bash.rc
此时执行内容为 echo “$WANG”的 脚本
如用 ./sh.sh 则无输出 #./执行时是在起一个子shell
如用source sh.sh或 . sh.sh则输出ni hao #source是在本shell中执行
---------------------------------------------------------------------
bash shell元字符(通配符)
\ 按字面含义解释后面的那个字符
& 在后台处理的进程
; 分隔命令
$ 替换命令
* 匹配任意字符
? 匹配任意单个字符
[...] 匹配[]中的任意一个字符
[!...] 不匹配[]中!的任意一个字符
(cmds) 在子shell中执行命令
{cmds} 在当前shell中执行命令
---------------------------------------------------------------------
文件名置换
计算命令行时,shell会用元字符来缩写能够匹配某个特定字符组的文件名或路径名
将元字符展开为文件名或路径名的过程称为文件名替换或globbing
* 匹配文件(夹)名中的任意字符串
如:ls app*
cd cmdd*
? 匹配文件(夹)名中的任意一个字符
[...] 匹配[]中的任意一个字符
[!...] 不匹配[]中!的任意一个字符
如:ls [a-z]*.o #匹配以a-z开头的已.o结尾的文件
ls [!0-9]*.o #匹配以非0-9开头的已.o结尾的文件
---------------------------------------------------------------------
命令执行顺序
命令1 && 命令2 #命令1执行成功才会执行命令2
命令1 || 命令2 #命令1执行不成功才会执行命令2
用() 和 {}将命令结合在一起
---------------------------------------------------------------------
Bash shell变量
变量可分为两种:局部变量和环境变量
局部变量只在创建他们的shell中可用,环境变量作用域可以扩展到子shell中去
变量命名规则:可以是字母、0-9、下划线组成,必须以字母或下划线开头,其他字符都标志着变量名的终止,变量名大小写敏感
有两个内置命令可以用来创建变量,他们是declare、typset,其选项可以控制变量的设置方式,建议使用declare.
格式:declare [选项] 变量=值
选项:-x 将变量设置成环境变量
-r 将变量设置成只读变量
-a 将变量当一个数组
---------------------------------------------------------------------
创建局部变量
1:变量赋值:变量=值 #注意等号周围不能有任何空白字符,如果想赋空,可以在等号后跟上换行符
2:内置命令declare 变量=值 #注意等号周围不能有任何空白字符,如果想赋空,可以在等号后跟上换行符
例子:
设置:round=world 或 round=”world nice” #“”保护空白符
设置:declare round=world
输出:echo $round
设置:file.bak=”xxxx” 错,变量名中出现非法字符
local函数:函数内创建局部变量可以用local函数
---------------------------------------------------------------------
创建环境变量
环境变量,又被称为全局变量,作用域可以扩展到子shell中,通常环境变量用大写
环境变量是已经用export内置命令导出的变量,如果想设置环境变量,只需在设置变量时或赋值后使用export命令即可,declare 带-x也是设置环境变量
设置环境变量:
1:export 变量=值 #注意等号周围不能有任何空白字符,如果想赋空,可以在等号后跟上换行符
2:变量=值; export 变量 #注意等号周围不能有任何空白字符,如果想赋空,可以在等号后跟上换行符
3:declare -x 变量=值 #注意等号周围不能有任何空白字符,如果想赋空,可以在等号后跟上换行符
---------------------------------------------------------------------
设置只读变量
只读变量是不能被重新定义或复位的特殊变量,但是如果使用declare定义的变量,可以重定义,不能复位
设置:name=”TOM”
readonly name #设置只读
unset name #不能复位
name=Jem #不能重定义
设置:declare -r city=”shanghai”
unset city #不能复位
declare city=“beijin” #可以
---------------------------------------------------------------------
提取变量的值
在变量前加$
---------------------------------------------------------------------
复位变量
只要不被设置只读,局部变量和环境变量都可以用unset命令复位
格式:unset 变量名
---------------------------------------------------------------------
显示变量值
1:echo [选项] 变量 #echo将他的参数显示到标准输出上
选项:-e #允许解释转义字符,如echo -e “\a” \a转义为报警
如:echo The name is $NAME
echo -e “\a” #报警
2:printf命令
---------------------------------------------------------------------
变量扩展修饰符
可以用一些专用修饰符来测试和修改变量,修饰符首先进行简单的条件测试,检查某变量是否已被设置,然后根据测试结果给变量赋值
${VA:-word} #如变量VA已经设置且非空,则代入其值,否则代入word 临时替换默认值
${VA:=word} #如变量VA已经设置且非空,则代入其值,否则VA设置为word,代入VA永久替换默认值
${VA:+word} #如变量VA已经设置且非空,则代入word,否则代入空值 临时替换默认值
${VA:?word} #如变量VA已经设置且非空,则代入其值,否则输出word且从shell退出 基于默认值创建错误信息
注:不加冒号时,值为空也被认为已经设置
如:echo ${name-Joe} #结果为空
echo ${name:-Joe} #结果为Joe
echo ${namex:?”namex is undefined”}
echo ${y?} #如果y未设置,否则输出parameter null or not set
${VA:offset} #获取变量VA值中位置从offset开始的字串
${VA:offset:length} #获取变量VA值中位置从offset开始长度为length的字串 创建字串
如:var=notebook
echo ${var:0:4} #结果note
---------------------------------------------------------------------
子串的变量扩展
模式匹配变量用来在串首或串尾截掉串的一部分,常用语删除路径名的头或尾
${变量%模式} #将变量值的尾部与模式进行最小匹配,并将匹配到的部分删除
${变量%%模式} #将变量值的尾部与模式进行最大匹配,并将匹配到的部分删除
${变量#模式} #将变量值的头部与模式进行最小匹配,并将匹配到的部分删除
${变量##模式} #将变量值的头部与模式进行最大匹配,并将匹配到的部分删除
${#变量} #替换为变量中的字符个数,如果是*或@ ,长度则是位置参量的个数
如:
pathname=”/usr/bin/local/bin”
echo ${pathname%/bin*} #结果/usr/bin/local/
echo ${pathname%%/bin*} #结果/usr
echo ${pathname#/usr} #结果/bin/local/bin
echo ${pathname##/usr} #结果bin
echo ${#pathname} #结果8
---------------------------------------------------------------------
位置参量
下面这组专用内置变量常称为位置参量,通常被shell脚本用来从命令行接受参数,或被函数用来保存传递给它的参数
$0 #指当前shell脚本的名称
$1-$9 #代表第一个到第9个位置参量
${10} ${11} #第10、11个位置参量,不用$10,$11
$# 其值为位置参量的个数,不含$0
$* 其值为所有的位置参量
$@ 同$*
“$*” 其值为“$1 $2 $3”
“$@” 其值为“$1”“$2”“$3”
位置参数可以用set命令来设置、重置或复位
set -- #清除所有的位置参数
---------------------------------------------------------------------
其他特殊变量
$ #当前shell的pid
_ #当前sh的选项设置
? #已执行的上一条命令的退出值
! #最后一个进入后台的作用的pid
---------------------------------------------------------------------
引用
用来保护特殊的元字符不被解释和禁止参量扩展
引用有三种方式:反斜杠、单引号、双引号
需要引用的特殊元字符有:
;
&
()
{}
|
< >
空格 tab 换行符
$
* [] ?
1:单引号和双引号必须成对出现
2:单引号保护特殊元字符免受解释,双引号也能,但双引号允许处理变量替换字符$和命令替换字符``和\
3:双引号可以保护单引号,单引号可以保护双引号
4:如果有不匹配的引号,bash会出现次提示符
反斜杠:反斜杠用于引用(或转义)单个字符,使其免受解释。
单引号中的反斜杠不会被解释
如果在双引号中,反斜杠将保护$ ``和反斜杠免受解释
单引号:成对出现,保护所有元字符不被解释,打印双引号就必须用双引号将其括起来,或反斜杠转义
双引号:同单引号,但是允许进行变量替换$和命令替换``和\
简言之:单引号中什么都不被解释。双引号中$ `` \这三个会被解释,如不想解释用\转义
注意:``同$()是一样的,所以$(date)也会展开
---------------------------------------------------------------------
命令替换
命令替换的用处是将命令的输出结果赋给一个变量或将命令的输出结果代入命令所在位置
bash 允许使用两种格式:`命令` 和 $(命令)
执行扩展时,bash先执行命令,然后返回命令的标准输出,输出结果末尾的换行符都将被删除,如果不想删除,可用“”括起,如:echo “$(cal)”
如:echo “this is `date +%H`” #this is 09
d=$(date) #d存放命令date的结果
`命令` \保留字面意思,除非后面跟$ ` \ 且``中$ \生效,可用\转义之,``中再有``的话必须用\转义
$(命令) 中的所有特殊字符都不会解释
命令替换可以被嵌套,``必须使用\`转义,如echo `basename \`pwd\` ` #其中转义后的`pwd`也是当做命令替换的,如
:$(basename $(pwd))
---------------------------------------------------------------------
数组
bash 中可以创建一维数组,数组允许将一列词放到一个变量名中,可以用内置命令declare -a创建,或直接给变量名一个下标来创建,如x[0]=5
索引值为从0开始的整数,数组无上限,索引也不必是有序数。
取出数组中某个元素,语法为:${数组名[索引]}
创建数组:
declare 、local 、read-only内置命令也可以带-a选项来声明一个数组。read -a是读取一列词到数组中
declare -a va_name=(item1 item2 item3 ...)
declare -ar va = {item1 item2 item3 ...}
states=(ME [3]=CA [2]=CT) #数组states第0元素为ME 3元素为CA 2元素为CT
declare -a nums=(45 33 100 65)
name=(TOM Dick Harry)
echo ${va_name[*]} #输出数组所有元素
echo ${#va_name[*]} #输出数组大小
取消定义:unset name 或 unset name[2]
---------------------------------------------------------------------
函数
bash函数用于在当前shell环境(不派生子shell)通过函数名执行一组命令,函数常常用于提高脚本的模块化程度。
函数可被重复调用。函数必须定义后才会被调用
定义函数:有两种格式声明一个bash函数
1:函数名后跟一对圆括号,再跟函数定义
function_name () { commands;commands; }
2:function关键词后跟函数名及函数定义,圆括号可选
function function_name { commands;commands;}
function function_name () { commands;commands;}
注意:命令之间用;隔开,最有一条命令必须以分号终结。花括号两侧空格是必须的。
传递给函数的任何参数被当做函数内的位置参数,一个函数的位置参数相对于函数来说是局部的
内置命令local允许在函数定义中创建局部变量
函数可以递归调用本身
函数中的命令是在当前shell环境下执行
全局函数:同变量一样,函数作用域可以扩展到子shell,只要用export -f全局化函数
export -f 函数名
说明:当函数命令列在单独的行,可以不用分号,最后一条还是需要。如果列在同一行,必须用分号隔开
如:function welcome { echo “Hi $1 and $2”; }
welcome tom joe #传递参数给函数,结果为Hi tom and joe
set jane anna lizzy
echo $1 $2
jane anna
unset -f welcome #清除函数定义
列出和清除函数
declare -f #列出该shell中定义的所有函数及他们的定义
declare -F #同上,只列出函数名
unset -f #清除函数定义
---------------------------------------------------------------------
管道
管道(pipe)将管道符左侧命令的输出作为到管道符右侧命令的输入,一条管道线可能不止一个管道
管道符用竖杠 | 表示,一般形式:命令1 | 命令2 | 命令3
---------------------------------------------------------------------
shell内置命令
shell中有许多内置到它的源码中的命令,shell无需到磁盘中定位他们,执行速度速度快很多。
常见内置命令如下:
: #空命令
. #在当前进程的环境下执行程序,同source
alias #命令重命名
unalias #删除重命名
bg #将作业放到后台
cd
exit
fg #将作业放到前台
jobs #列出放在后台的作业
set #设置选项和位置参数
unset #删除变量值或函数
declare
export
---------------------------------------------------------------------
Bash shell编程
shell脚本:当命令不在命令行上执行,而是通过一个文件执行时,该文件被称为shell脚本,脚本以非交互的方式运行。它先查找环境变量所指定的环境文件,通常为
.bashrc,然后从该文件开始执行,然后才开始执行脚本中的命令
创建shell脚本的步骤:
1:第一行:#!/bin/bash
2:编写内容
shell脚本结构:由一组Unix/linux命令、bash shell命令、程序结构控制语句、注释 组成
3:增加执行权限 chmod +x files
---------------------------------------------------------------------
读取用户输入
read命令
read是一个内置命令,用于从终端或文件读取一个输入行,直到换行符,行尾的换行符被转换成一个空字符,如果后面未跟变量名,则读取的行被赋给内置变量REPLY,
可以用read中断脚本的运行,直至输入回车键
read var #把读入的数据全部赋给var
read var1 var2 var3 #把读入一行的第一、二个词分别赋给var1、var2,其他的都赋给var3
---------------------------------------------------------------------
算术运算
整数运算(declare和let命令)
declare命令:可以用declare -i 定义整形变量,如果给一个整形变量赋一个字符串,则bash将把变量赋值为0,可以对已定义的整形变量执行算术运算(
如果未定义为整形变量,内置的let命令也允许算术操作),如果给整形变量赋一个浮点数值,则bash报语法错误。数字可以用不同基数的数字表示
如:declare -i num
num=5 + 5 #错
num=5+5 #对
num=”5 + 5” #对
num=5.6 #错
declare -i 将列出所有已经设置的整形变量及其值
用不同的基数表示数字
格式:variable=base#number
如:declare -i x=017
x=2#101
x=8#17
let命令:let命令式bash shell内置命令,用来执行整形算术运算和数值表达式测试;可用(())表示let命令
let命令在执行算术运算时,不需要用$来展开变量,参数含有空格则用“”包含
如:let “i = i + 2”
---------------------------------------------------------------------
位置参数
用户可以通过命令行向脚本传递信息,跟在脚本名后的用空白符分隔的每个词都称为参数,可以在脚本中使用位置参数来引用命令行参数
shell环境中的位置参数作用域在本shell,shell脚本执行时跟在后面的参数相当于局部的位置参数,只对本脚本生效
如:脚本内容 echo “$1”
执行时 source sh.sh wang #则输出wang
如果在命令行set hahaha
执行时 source sh.sh wang #则输出wang
执行时 source sh.sh #则输出hahaha
set命令与位置参数
可以用set命令设置或重设位置参数
带参数的set命令将重置位置参数,重置的是shell环境中的位置参数。清除所有位置参数,可以用set -- 命令
---------------------------------------------------------------------
条件结构和流程控制
条件结构能够根据某个特定的条件是否满足,来执行相应的任务
bash可以检测两种类型条件:命令成功或失败,表达式为真或假。在任何一种类型的测试中,都要使用退出状态,为0表示命令成功或表达式为真,非0
表示命令失败或表达式为假。退出状态保存在状态变量?中
简言之:bash中执行命令成功与否和表达式为真或假都会改变退出状态变量?
内置命令test
单方括号的test命令:通常使用内置的test命令测试表达式的值,test命令可以被链接到方括号上,这样即可使用单独的test
命令,也可通过把表达式用单括号括起来,来测试表达式的值
用test命令或[]测试表达式时,表达式中的shell元字符不会被解释。由于对变量进行单词分离,因此包含空白符的字符串必须用引号括起来
双方括号的test命令:用[[]]来测试表达式的值,其中对变量不进行单词分离,但可以通过元字符扩展进行模式匹配。包含空白符的字符串必须用引号括起来,
如果一个字符串(不管含不含空白符)仅仅是在表达式中作为一个普通字符串,而不是一个模式的一部分,则必须用引号括起来
逻辑操作符&&、||代替了与test命令一起使用的-a -o选项
说明:test可以用来测试字符串、数字、文件。test命令中表达式等号两侧必须有空格。单方括号第一个方括号后必须有空格,表达式两侧必须有空格。
简言之:
[]的测试表达式:表达式可为字符串比较、数字比较、文件测试。表达式等号两侧必须有空格,方括号必须有空格。表达式中的shell
元字符不会被扩展。对变量进行单词分离,所以包含空格时必须用引号括起来
[[]]的测试表达式:表达式可为字符串比较、数字比较、文件测试。表达式等号两侧必须有空格,方括号必须有空格。表达式支持shell
元字符,如果为普通字符串,防止误认为模式,必须用双引号括起来。支持逻辑&& || ,对应test中的-a -o
,其中对变量不进行单词分离,即使变量由多个词组成也不需要双引号括起来
let和带双圆括号的算术运算符(())
对于计算算术表达式,可以不用test而用let命令,let命令含有丰富的操作符,let命令等同(())
(())中的变量不需要使用$,操作符两侧必须空格,圆括号两侧必须空格
简言之:let命令更适合整形算术运算和数值表达式测试
---------------------------------------------------------------------
if命令
if 结构后面的命令可以是bash内置命令或可执行程序,如ls
bash shell中跟在if后面的则是一条或一组命令。
exit 命令和变量? exit用于终止脚本并返回到命令行
检查空 检查变量的值是否为空时,必须用双引号把空括起来,否则test命令失败
if 命令
then
命令
elif 命令
then
命令
elif 命令
then
命令
fi
---------------------------------------------------------------------
null命令(shell内置命令)
:代替null命令
null命令不做任何事,只是返回退出状态0(注意没退出,不同于exit 0)
---------------------------------------------------------------------
case命令
格式:
case 变量 in
表达式1)
命令组
;;
表达式2)
命令组
;;
...
*)
命令组
;;
esac
变量的值逐一与表达式相比,符合则执行命令组,并跳到esac后继续执行
表达式可以使用shell通配符,还可以使用 | 将两值相或
---------------------------------------------------------------------
循环命令
bash shell提供三种类型的循环:for while until
---------------------------------------------------------------------
for命令
格式:
for 变量 in 词表
do
命令组
done
注:词表可以通过执行命令获得,如 for W in $(date)
词表支持shell元字符:如 for file in memo[1-5]
注意词表是$* $@ “$*” “$@”时的区别
如果没有“in 词表”则相当于“ for 变量 in $* ”
如果命令行参数为*,则它表示当前目录下的所有文件。
---------------------------------------------------------------------
while命令
格式:
while 测试命令
do
命令(命令组)
done
注:while 后的测试命令可以用test 或let或其他
---------------------------------------------------------------------
until命令
同while命令,只不过相反,也就是until 后的命令执行不成功时执行命令组
---------------------------------------------------------------------
循环控制命令
shift命令
shift 命令将参数左移指定次数,如:shift 5,没给参数时移动一次,当不够移动时,输出信息。
shift常用于while循环中遍历位置参数列表时。
如:while (( $# > 0 ))
do
echo $1 #$1值不断变化
shift
done
ture命令:总是已状态0退出
break命令
break用于跳出循环,层数为跳出几层
continue命令 跳过本次循环,继续下次,参数为调到哪一层循环起点,默认为跳到最近一层
---------------------------------------------------------------------
I/O重定向 与 子shell
shell可通过管道或重定向将输入从文件输入改为从循环读取输入,输出到循环改为输出到文件
shell启动一个子shell来处理I/O重定向和管道,循环结束后,在循环中定义的所有变量对脚本的其余部分都是不可见的
重定向一般是到文件,管道一般是到命令
将循环的输出重定向到一个文件:bash循环的输出不仅可以送到标准输出,还可以通过管道送到文件
将循环的输出管道到一个命令
---------------------------------------------------------------------
后台执行循环
循环可以在后台执行,这样就可以继续往下执行其他程序而不必等待循环处理全部完成
---------------------------------------------------------------------
函数
函数在当前环境中运行,函数共享调用它的脚本中的变量,还允许给函数传递参数,可以使用local功能在函数内部创建局部变量
在函数中调用exit将退出整个脚本。
函数中的return语句,返回函数执行的最后一条命令的退出状态,或返回指定参数值
使用export -f把函数导出到子shell
使用declare -f可以列出所有的函数名及其定义
如果函数保存在其他一些文件中,可以用source和dot命令把他们载入到当前脚本中
函数可以递归调用,次数没限制
清除函数
从内存中清除某个函数,使用unset命令
unset 函数名
函数的参数和返回值
当前shell环境中的变量对函数是可见的,在函数中对环境所做的任何改动也是会对shell环境生效的。
函数可以使用位置参数向函数传递参数,位置参数是函数私有的,也就是说,函数对参数的操作不会影响在函数外使用的任何位置参数
内置local功能:函数私有的局部变量,在函数退出后随即消失。
内置return命令:用来退出函数并将控制回转到程序调用函数的位置,如果未给return赋值,则返回最后一条命令的退出状态,如果赋值了,则该值保存在变量?
中。可以是0-255之间整数。
获取函数的结果可以用 命令替换,如:$(函数名) `函数名`
函数可以定义在文件中,当需要时,调用source或dot命令跟上函数名就能激活文件中的函数,函数会被加载到shell内存空间
---------------------------------------------------------------------
调试
带-n选项的bash命令,能对脚本进行语法检查,但不去运行任何一条命令,如语法错误,则报错,否则不显示任何内容
最常见的调试脚本的手段是用带-x选项的set命令,或是调用带-x选项和脚本名为参数的bash
此时shell对脚本的每条命令处理过程为:先执行替换,接在显示,再去执行它。shell显示脚本中的行时,会在行首添加加号+
调试选项:
bash -x 脚本名 #回显 在变量替换之后,执行命令之前,显示脚本的每一行
bash -v 脚本名 #详细 在执行之前,按输入的原样打印脚本中的各行
bash -n 脚本名 #不执行 解释但不执行命令
set -x #打开回显 跟踪脚本执行
set +x #关闭回显 关闭跟踪功能
---------------------------------------------------------------------
调试shell脚本
风格问题
1:加注释
2:定义有意义的变量名
3:确保健壮性
错误类型
---------------------------------------------------------------------