一、运行Shell脚本
shell基础
#! 是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种 Shell。
执行脚本
执行脚本的两种方法:
1.
chmod 755 file.sh 先修改可执行权限
cd到当前目录下
使用 ./file.sh file.sh为执行的脚本名称
2.通过bash调用
bash file.sh
如果是html文本
使用firefox浏览器执行: firefox file
使用echo命令进行文本时,使用的引号可以包含换行符,因此可以包含多个文本行。
使用echo -e选项可以支持\控制的字符转换
变量和常量
创建变量和常量
创建变量直接创建 例如: foo="hello"
运用时 需使用 $+变量名
强制常量不发生变化 使用declare命令的-r选项
declare -r foo="hello" foo后面将不会再被改变 相当于c++z中的const
为变量和常量赋值
shell并不关心赋给变量的值的数值类型,可以通过declare命令的-i选项,强制shell将变量限制为整数类型。
在赋值时,变量名、等号和值之间不能含有空格。
a=z 将字符串z赋值给a
b="a string" 嵌入的空格必须用引号引起来
c="a string and $b" 可以被扩展到赋值语句中的其他扩展、比如变量
d=$((5*7)) 算术扩展
e=$(ls -l foo.txt) 命令的结果
f="\t\ta string\n" 转义序列 比如制表符和换行符
可以在一行中对多个变量赋值。
当字符变量因为上下文变得并不明确时 可以使用{}
here文档
除了使用echo命令进行文本输出,here文档是I/O重定向的另一种形式。
工作形式如下:
command << token
text
token
其中command是接收标准输入的文件名,token是用来指示嵌入文本结尾的字符串。
cat << _EOF_
...
_EOF_
_EOF_被选作token,表示文本的结尾 token必须单独一行出现,并且文本行的末尾没有空格
二、自顶向下设计
shell函数
shell函数有两种语法形式:
function name{
commands
return
}
其中name是指这个函数的名称,commands是这个函数的一系列指令
name(){
commands
return
}
局部变量
局部变量是通过在变量名前添加单词local来定义。
三、if分支语句
使用if
if语句的语法格式:
if commands; then
commands
[elif commands; then
commands...]
[else
commands]
fi
commands可以是一组命令 可使用;隔开
会以最后一个命令的执行结果作为评判标准
退出状态
命令在执行完毕后,会向操作系统发送一个0~255的值,用来指示命令执行成功还是失败。其中,数值0表示成功,其他的值表示执行失败。
对于每个命令可以检测退出状态:
echo $? 输出0表示成功退出
使用test命令
test命令经常与if一起使用,会执行各种检查和比较。
有两种等价的形式:
test expression 或者 [ expression ]
其中expression是一个表达式,其结果是true或false
[]间必须有空格
下面介绍一些表达式expression
文件表达式
测试文件的表达式用来评估文件的状态:
表达式 成为true的条件
file1 -ef file2 file1与file2拥有相同的信息节点编号
file1 -nt file2 file1比file2新
file1 -ot file2 file1比file2旧
-b file file存在并且是一个块文件
-c file file存在并且是一个字符文件
-d file file存在并且是一个目录
-e file file存在
-f file file存在并且是普通文件
省略其余部分 参考p332
字符串表达式
测试字符串的表达式用来测试字符串的操作:
表达式 成为true的条件
string string不为空
-n string string的长度大于0
-z string string的长度等于0
string1=string2 string1和string2相等,双引号使用更多
string1==string2
string1!=string2 string1不等于string2
string1>string2 在排序时,string1在string2后
string1<string2 在排序时,string1在string2前
在使用’<’ '>'时,必须用引号括起来,或者使用反斜杠进行转义,不然会被解释为重定向符号。
整数表达式
整数判断操作:
表达式 成为true的条件
a -eq b a与b相等
a -ne b a与b不相等
a -le b a小于等于b
a -lt b a小于b
a -ge b a大于等于b
a -gt b a大于b
e equal n not l less g greater
更现代的test命令版本
语法: [[ expression ]] expression是一个表达式 结果为true或false
增加了很重要的新字符串表达式:string1=~regex
x=-5
if [["$x"=~ ^-?[0-9]+$ ]] then...
如果string1与扩展的正则表达式regex匹配,则返回true
[[]] 另一个特性是==操作符支持模式匹配:
file=foo.bar
if [[ $file==foo.* ]];then...
[[ 和 ]]之间不能有空格
组合表达式
与test和[[]]命令配套的逻辑运算有三个,分别是AND,OR,NOT
逻辑操作符:
operation test [[]]或(())
AND -a &&
OR -o ||
NOT ! !
由于test命令使用的所有表达式和操作符都被shell看作命令参数,不像[[]]或(())一样,因此在bash中含有特殊含义的字符如’<’,’>’,’(’,’)'必须使用引号括起来或者进行转义。
四、读取键盘输入
read命令 从标准输入读取输入值
内嵌命令read的作用是读取一行标准输入。
可用于读取键盘输入值或应用重定向文件读取文件的一行。
read命令的语法结构为:
read [-options] [variable...]
options为参数选项, variable是一到多个用于存放输入值的变量
read常用的参数选项
-a array 将输入值从索引为0的位置开始赋给array
-d delimiter 用字符串delimiter的第一个字符标志输入的结束,而不是新的一行的开始
-n num 从输入中读取num个字符,而不是一整行
-p prompt 使用prompt字符串提示用户进行输入
-r 原始模式 不能将后斜线字符翻译为转义码
-s 保密模式 不在屏幕显示
-t seconds 超时,在seconds秒后结束输入
-u fd 从文件说明符fd读取输入,而不是从标准输入中读取
如果read命令读取的值少于预期的数目,则多余的变量值为空,而输入的值数目超过预期的数量时,最后的一个变量包含了所有的多余值。
如果read命令后无变量,则会为所有输入分配一个shell变量:REPLY
使用IFS间隔输入字段
通常shell会间隔提供给read的内容,此行为有shell变量IFS设定,IFS设定值包含空格、制表符、换行符。
如果已知数据,不需要从键盘读取,可以使用’<<<'操作符,象征一条嵌入字符串。
read不可重定向!
五、WHILE和UNTIL循环
while
while循环的语法结构:
while [ 条件判断语句 ]
do
程序
done
或者
while commands; do commands; done
如需跳出循环,可使用continue和break语句 ,同c语言用法
until
while命令退出状态不为0时终止逊环,而until命令则刚好相反。
如果添加判断式不成立,则循环,成立则退出循环。
语法结构同while循环
使用循环读取文件
while与nutil可处理标准输入。
为了将一份文件重定向到循环中,可以在done后添加重定向符号,实例:
while read a b c; do
...
done < foo.txt
从foo.txt文件中读取a b c 参数
还可以使用管道进行读取:
sort -k 1,1, -k 2n foo.txt | while read a b c; do
...
done
此脚本或取sort命令的输出,但是,管道是在子shell中进行循环,所以循环终止时,
循环内部新建的变量或对变量的赋值效果都会丢失。
六、case分支
bash的多项选择符合命令被称为case。case只能判断一种条件关系
其语法形式为:
case word in
[pattern [| pattern]...) commands ;;]...
esac
简化
case $变量名 in
1)
commands
;;
2)
commands
;;
esac
模式
case使用’)'字符结尾的模式。
case模式范例:
a) 若关键字为a则吻合
[[:alpha:]] 若关键字为单个字母则吻合
???) 若关键字为三个字符则吻合
*.txt) 若关键字以.txt结尾则吻合
*) 任何关键字都吻合
多个模式的组合
使用竖线作为分隔符来组合多个模式,满足其一即可。
七、位置参数
位置参数变量有
$n n为数字,$0代表命令本身,$1-$9代表第一到第九个参数,十以上的参数需要用大括号例如 {$10}
$* 这个变量代表命令行中所有的参数,把所有的参数看成一个整体
$@ 这个变量也代表命令中所有的参数,不过$@把每个参数区分对待
$# 这个参数代表命令行中参数个数
八、For循环
原始的for命令语法如下:
for variable [in words]; do
commands
done
其中,variable是一个在循环执行时会增加的变量名,words是一列将按顺序付给变量variable的可选项,commands部分是每次循环需要执行的命令。
for i in A B C D;do
echo "$i"
done
c语言形式:
for (( expression1;expression2;expression ));do
commands
done
其中expression1,expression2,expression3为算术表达式,commands是每次循环都要执行的命令。
for (( i=0;i<5;i++ ));do
echo $i
done
九、字符串和数组
参数扩展
基本参数
普通变量用{}括起来防止shell将其与邻近文本混淆。
空变量扩展的管理
有的参数扩展用于处理不存在的变量和空变量。在解决缺失的位置参数和给参数赋默认值时很有用。
形式为:
${parameter:-word}
如果参数parameter未被设定或是空参数,则其扩展为word的值,如果非空,则为parameter的值
${parameter:=word}
如果参数parameter未被设定或是空参数,则其扩展为word的值,如果非空,则为parameter的值
${parameter:?word}
如果参数parameter未被设定或是空参数,则会导致脚本错误并退出,并且word内容输出到标准错误,如果非空,则为parameter的值
${parameter:+word}
如果参数parameter未被设定或是空参数,则不产生任何扩展,如果非空,则为word的值
返回变量名的扩展
${!prefix*}
${!prefix@}
该扩展返回当前以prefix开头的变量名
字符串操作
${#parameter}
扩展为parameter内包含的字符串长度,一般来说参数parameter是个字符串,
如果参数parameter是"@"或"#",扩展结果就是位置参数的个数。
${parameter:offset}
${parameter:offset:length}
这个扩展用于提取一部分包含在参数parameter中的字符串,扩展以offset开始,直到字符串结尾,除非length指定。
如果offset的值为负,默认从字符串尾部开始,注意,负值前面必须要有空格,防止与${parameter:-word}混淆。
${parameter#pattern}
${parameter##pattern}
根据pattern定义,去除包含在parameter中的字符串的主要部分。
pattern是一个通配符模式,类似路径名的扩展。
两种形式区别在于 #形式去除最短匹配,##形式去除最长匹配。
${parameter%pattern}
${parameter%%pattern}
同上述扩展相同,只是此扩展从参数包含的字符串末尾去除文本。
${parameter/pattern/string}
${parameter//pattern/string}
${parameter/#pattern/string}
${parameter/%pattern/string}
此扩展在parameter的内容上可执行搜索和替换,如果文本和pattern一致,则被替换为string的内容。
通常形式下,只有第一个pattern被替换,在"//"形式下,所有的被替换,在"/#"形式下,要求匹配出现在字符串开头,在"/%"形式下,要求匹配出现在字符串末尾。
/string可省略,不过匹配的内容将会被删除。
十、数组
创建一个数组
命名数组变量同其他bash变量一样,访问时可以自动创建
a[1]=foo
使用declare命令也可以创建数组:
declare -a a 使用declare的-a 选项创建数组名为a
数组赋值
name[subscript]=value name是数组名,subscript是>=0的整数
name=(value1,value2...) 为数组多个位置赋值 从下标0开始
name=([0]=1 [2]=3 [5]=6) 为特定位置赋值
数组操作
输出数组的所有内容
使用下标"@“和”*“访问数组的每个元素,注意使用”“与不使用”"遍历时不同。
确定数组元素的数目
使用#符号
查找数组中使用的下标
${!array[*]}
${!array[@]}
array是数组变量名,遍历时输出数组中赋有值的位置
在数组的结尾增加变量
使用+=符号
foo=(a b c)
foo+=(e d f)
数组排序操作
a=(a b c d e)
a_sorted=($(for i in "${a[@]}";do echo $i;done | sort))
使用复制数组,遍历a数组 然后调用sort命令进行输出
数组的删除
使用unset命令进行删除整个数组。 直接 unset 数组名
删除单个数组元素 unset ‘数组名[位置]’
对数组赋空值,只会删除数组的第一个位置,即0位置