字符表示相关:
没有被单引号括起的’\’表示其后所接的字符为字符字面意义。除了在行末表示两行连接。
单引号括起表示单引号内左右字符为字面意义,其中不能再出现单引号,即使前面加反斜线’\’。
双引号括起表示其内部所有的字符为字面意义,但 ’$’, ‘`’, ‘\’,’!’例外
’$’, ‘`’ 保持特殊意义,’\’只有在’$’, ’`’, ’”’ , ’\’,换行字符跟随时才保留特殊意义
’\’后字符没有特殊意义的,不做修改
双引号内可以使用双引号,但要加’\’。
‘!’保留特殊意义,除非前面加‘\’
特殊参数‘*’和’@’在双引号内有特殊意义
ANSI-C
变量:
等号两侧不能加空格,如果加空格,那么Shell会认为是执行name命令加上参数
命名方式与c类似
$1,$2,$3等是Shell用来解析命令行参数的特殊变量,只读不可写
当Shell遇到$时,首先读取符号$后面的一个字符串,把这个字符串当作一个变量名,然后依据这个变量名读取出变量的值,然后代替$符号和变量名整体。这叫变量替换
Shell脚本中的变量可以不用事先定义直接引用,如果为空则相当于空变量,返回一个空字符
read命令可以把用户的输入赋值给变量,unset可一删除一个定义过的变量
为了某一个程序在一个特定的环境执行,而不改变当前的shell命令,可以使用如下形式
var1=value,var2=value,var3=value... program
readonly定义只读变量
两种方法:
1:
VERSION=2.0
readonly VERSION
2:
readonly VERSION=2.0
数组变量:
${arr[*]}为数组作为一个整体进行替代,而${arr[@]}是作为元素列表进行替代。"${arr[@]}"与${arr[*]}等价
for i in "${arr[@]}" 和for i in ${arr[*]}和for i in ${arr[@]}的输出是相同的
但for i in "${arr[*]}"是不一样的
${arr[*]}和${arr[@]}的不同在于加引号时的区别,不加时都是拓展为元素列表
${arr[*]}加引号拓展为整体,而${arr[@]}加引号时拓展为元素列表
双引号括起的就是一个字符串
for循环右边是多个元素,不是一个字符串进行分割
赋值方式:
array[index]=value
array=(value0 value1 value2) //会覆盖元素
array=([2]=value2 [0]=value0 [1]=value1) //会覆盖元素
删除变量:
unset arr[0]:删除一个元素
unset arr、unset arr[@]、unset arr[*]为删除整个数组
array=([2]=value2 value3 value4) 序号依第一个递增
${#arr[@]}获得数组元素个数
环境变量
export name=value
export name
子进程和父进程的同名环境变量所处的存储位置不一样,不能相互影响
Shell变量 man bash Shell Variables处有所有shell变量
HOME |
当前用户的主目录 |
SHELL |
当前用户所使用的Shell程序 |
USER |
当前的登录用户 |
UID |
拓展为当前用户数字的user id |
BASH_VERSION |
当前使用的bash版本 |
PWD |
当前工作目录 |
OLDPWD |
前一个工作目录 |
SECONDS |
shell执行了多长时间 |
SHLVL |
当前bash在shell的第几层子进程 |
RANDOM |
产生0到32767的随机数 |
IFS |
分隔符 |
PATH |
到哪些目录去搜索可执行文件 |
set命令可以查看Shell中所有的变量和函数定义,export -p 和env命令可以查看到所有被export导出到环境中的变量
特殊变量
特殊变量$#表示有多少个参数
可用内建命令shfit删除第一个参数,指定参数n可以使shift删除多个参数,shift "$#" 删除全部参数
$?上条命令执行的返回值,非0则发生错误
$$为进程所在的PID
$@代表命令行中的所有参数列表
$*代表命令行所有参数整体
流程控制
二元操作符
-eq |
等于 |
-ne |
不等于 |
-le |
小于等于 |
-gt |
大于 |
-ge |
大于等于 |
如果then和if [ ... ] 写在一行,then的前面需要加分号
elif不能写成else if
如果使用elif语句,后面也要加then
不要忘记结束标记fi
内建测试命令 [ ]方括号两边都得有空格,好歹也是命令啊
if语句后面接的是命令
即 [ 是个命令,后面的表达式、] 都可以认为是选项。
if语句后面的返回值是0,则认为条件满足
case语句
语法:case word in [[(]pattern [|pattern]...) command-list ;;]... esac
case "$option" in
"O"|"o")
echo "successed!"
;;
*)
command-list
;;
esac
每个子句需要;;、;&或;;&来结束,区别在于
;;为即使后面还有匹配的pattern也不会执行子句
;&为结尾会继续执行下一个子句中的command-list,如过下个子句的结尾以;&或;;&结尾,那么按照相应规则一直到;;结尾,具有传递性,一发不可收拾
;;&为结尾会以执行后面子句中,符合pattern的。
while循环
语法:while test-commands; do consequent-commands; done
do标志循环体的开始。
test-commands可以是多个命令构成的一个list,由分号分开每个命令,决定是否退出循环的是最后一个命令的返回值。
until循环
语法:until test-commands;do consequent-commands;done
字符串操作符
用的和字符和数字的操作符是不一样滴
-n STRING |
长度非0返回真 |
-z STRING |
长度为0返回真 |
STRING1 = STRING2 |
字符串相同返回0 |
STRING1 != STRING2 |
两个字符串不相同返回真 |
for循环
语法:for name [in [words ...];] do cpmmands;done
for FILE in *.sh
c式for
for( ( i=1;i <= 100; i++))
单括号改为双括号,花括号改为do和done,变量不用加$。连空格都不用在意了。
select循环
语法:select name [in woeds...] ;do commands;done
无论输入什么,都会保存到变量$REPLY中
如果输入的数字和显示的标号不匹配,则不会保存到name中
无论用户输入与菜单项数字是否匹配,都会执行do和done之间的循环体。没有输入直接按ehter键什么也不执行,与再次执行select语句一样再次输出所有的菜单项和提示符。会执行select之前的语句。
循环体执行需要手动break或exit
select的循环默认提示符是#?,可在脚本开始后加入PS3="Please make a selection =>"
break和continue语句
break [n] continue [n]
函数
NTMD终于到你了。
定义格式
name()
{
command-list;
}
function name() 这里括号可省
{
command-list;
}
定义函数时函数体不能为空,调用函数时不加括号()。$0是脚本的执行路径,对于脚本来说
命令行里可以定义函数,用declare -f 查看所声明的函数定义,用unset取消函数声明。
参数
使用$1引用第一个参数,剩余类似。
注意$0仍然引用脚本名称。
使用例子,分解$1保存的IP:
local IFS=. //设置分隔符,local修饰表示只在本函数内生效
set -- $1 //拆散$1,保存在$1,$2,$3,$4.这会摧毁其它参数。
注意不要混淆函数输出和退出状态,函数也可以用命令替换。
变量作用域:函数内定义的,也是全局变量,可用local关键字声明局部变量,使作用域限制在函数内。但函数内定义的函数,只有外层函数被调用后才生效。脚本就是脚本。