@yangfch3
2017-01-14T11:01:31.000000Z
字数 5501
阅读 6518
shell
学习任何一门语言的基础都是:
所以,当新接触 Shell 编程,无非就是把这些在其他语言里学到的东西迁移与本土化。
sh/bash/zsh Shell 编程的局限
所以我们平时基本只使用 sh/bash 这些 Shell 语言 脚本来做一些轻量、自动化、琐碎的工作。
= 前后不能空格
Shell 负责与接收我们输入的命令,翻译成内核能接受的形式,帮助我们与内核(通过)Shell 命令/工具交流。
Shell 的语句以 ; 分隔或者换行以区分!
引号
注释以 # 为特征字符,但注释有两种用途:
放在 shell 文件头部指引解释器优先级
#!/bin/bash#!/bin/sh
普通注释
# Author: yangfch3# Copyright (c) http://yangfch3.com/
定义变量和使用变量存在着一定的规则
注意:变量名和等号之间不能有空格
变量命名规则:
$ 后接变量名${} 包住变量名推荐采用第二种写法,确保解析正确(帮助解释器识别变量的边界)。
name="yangfch3"echo "${name}"
使用未定义的变量,则变量值为空
echo "${name}"
与定义变量的方法一致,支持变量的复写
name="yangfch3"name="${name}@github"echo "${name}"
复写的变量的值就进行了更新
使用 readonly 关键字可以将一个变量设为只读
name="yangfch3"readonly name
或者直接放到变量前
readonly name="yangfch3"
如果你对只读的变量进行了复写,脚本会运行出错:
./main.sh: line 8: var1: readonly variable
使用 unset 可以删除变量
unset variable_name
1. 局部变量
在脚本或命令中定义,仅在当前shell实例中有效,其他shell启动的程序不能访问局部变量。
2. 环境变量
所有的程序,包括 shell 启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行。必要的时候 shell 脚本也可以定义环境变量。
3. shell 变量
shell 变量是由 shell 程序设置的特殊变量(见特殊变量一节)。shell 变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了 shell 的正常运行
特殊变量列表

命令行参数用 $n 表示,例如,$1 表示第一个参数,$2 表示第二个参数,依次类推。
echo "$1$2"
$ ./main.sh var1
var1
当 $n 中 n 的值小于参数个数时,$n 为空 ""
1. 不被双引号包含时
$* 和 $@ 都表示 传递给函数或脚本的所有参数,不被双引号(" ")包含时,都以"$1" "$2" … "$n" 的形式输出所有参数。
2. 被双引号包含时
当它们被双引号(" ")包含时,"$*" 会将所有的参数作为一个整体,以"$1 $2 … $n"的形式输出所有参数;"$@" 会将各个参数分开,以"$1" "$2" … "$n" 的形式输出所有参数。
echo "print each param from \$*"for var in $*doecho "$var"doneecho "print each param from \$@"for var in $@doecho "$var"doneecho "print each param from \"\$*\""for var in "$*"doecho "$var"doneecho "print each param from \"\$@\""for var in "$@"doecho "$var"done
输出:
print each param from $*abcprint each param from $@abcprint each param from "$*"a b cprint each param from "$@"abc
$? 可以获取上一个命令的退出状态。所谓退出状态,就是上一个命令执行后的返回结果。
退出状态是一个数字,一般情况下,大部分命令执行成功会返回 0,失败返回 1。
不过,也有一些命令返回其他值,表示不同类型的错误。
$ echo $?
0
$? 也可以表示函数的返回值(同脚本执行完毕相似)。
$0:当前脚本的文件名
$$:当前 shell 进程 ID
$#:传入的参数的个数
$ ./main.sh a b c
$0= ./main.sh
$#= 3
$$= 3333
类似于 ES6 里的模板字符串,shell 里的字符串内可以包含变量、转义字符……
echo -e "a\nb\nc"
注意:转义字符要想转换成功,需要为 echo 添加 -e 参数

命令替换是指 Shell 可以先执行命令,将输出结果暂时保存在变量中,在适当的地方输出或使用。
作用类似 ES6 里的模板字符串。需要将命令执行标准输出作为变量值得就是用 ``。
命令替换有两种模式:
$(put your command)(推荐)
echo "There are $(ls | wc -l) items here."UP=`date ; uptime`echo "Uptime is $UP"
变量替换可以根据变量的状态(是否为空、是否定义等)来改变它的值

echo ${var:-"Variable is not set"}echo "1 - Value of var is ${var}"echo ${var:="Variable is not set"}echo "2 - Value of var is ${var}"unset var # 删除变量 varecho ${var:+"This is default value"}echo "3 - Value of var is $var"var="Prefix"echo ${var:+"This is default value"}echo "4 - Value of var is $var"echo ${var:?"Print this message"}echo "5 - Value of var is ${var}"
输出:
Variable is not set
1 - Value of var is
Variable is not set
2 - Value of var is Variable is not set
3 - Value of var is
This is default value
4 - Value of var is Prefix
Prefix
5 - Value of var is Prefix
我们可以在读取变量时对变量内部进行字符串代换:
echo ${Variable/Some/A}# 会把 Variable 中首次出现的 "some" 替换成 “A”
我们也可以在读取变量时对变量字符串进行截取
# 变量的截取Length=7echo ${Variable:0:Length}# 这样会仅返回变量值的前7个字符
字符串的形式有如下几种:
区别其实比较容易区分,根据形式的特点决定使用何种方式。
无引号
单引号字符串的特点:
name='yangfch3'echo '\n${name}';
输出
\n${name}
双引号的特点:
双引号里内可以有 变量
双引号内变量可以再用双引号包住,也可以不包。
双引号里可以出现 转义字符
注意:shell 编程里没有所谓的字符串 + 的概念,直接在双引号内进行字符串拼接。
name="yangfch3"# 双引号递归匹配,内部双引号不会输出greeting="hello, "${name}" !"greeting_1="hello, ${name} !"echo $greeting $greeting_1
输出
hello, yangfch3 ! hello, yangfch3 !
string="abcd"echo ${#string} # 输出 4
string="xxx is a yyy"echo ${string:1:4} # 输出 xx i
string="xxx is a yyy"echo `expr index "$string" is` # 输出 4
bash 支持一维数组(不支持多维数组),并且没有限定数组的大小。
# 形式1arr1=("0" "1" "``expr 2 + 2")# 形式2array_name=(01`expr 2 + 2`)# 形式3:单独定义数组分量array_name[0]=0array_name[1]=1array_name[2]=`expr 2 + 2`
读取数组单项:${array_name[index]}
读取数组所有项:${array_name[*]} ${array_name[@]}
读取数组的长度:${#array_name[@]} length=${#array_name[*]}
读取数组单个元素的长度:lengthn=${#array_name[n]}
原生 bash 不支持简单的数学运算,但是可以通过其他命令来实现,例如 awk 和 expr,expr 最常用。
使用 expr 进行运算时需要使用上面提到的命令替换
`expr 2 + 2`
[] 在变量声明与分支判断时,内部也可以使用运算符:
num1=$[2*3] # 变量声明 [] 内部使用算术运算符if [num1 -eq 6] # 分支判断 [] 内使用运算符thenecho num1fi
() 内部也可以包裹运算 两点注意:
2+2 是不对的,必须写成 2 + 2,这与我们熟悉的大多数编程语言不一样。`,我们还可以使用()来包裹运算,如:(2 + 2)`
a=10b=20val=`expr $a + $b`echo "a + b : $val"val=`expr $a \* $b`echo "a * b : $val"if [ $a == $b ]thenecho "a is equal to b"fi

* 前边必须加反斜杠 \ 才能实现乘法运算;关系运算符只支持数字,不支持字符串,除非字符串的值是数字。
Shell 里对数值和字符串不做区分,或者说数值一般情况下视为字符串,再运算时才被当做数值。

a=10b=20if [ $a -eq $b ]thenecho "$a -eq $b : a is equal to b"elseecho "$a -eq $b: a is not equal to b"fi

a=10b=20if [ $a -lt 100 -a $b -gt 15 ]thenecho "$a -lt 100 -a $b -gt 15 : returns true"elseecho "$a -lt 100 -a $b -gt 15 : returns false"fi
在分支条件那里,我们可以使用 && 和 || 来进行 短路的逻辑运算。
# 在 if 语句中使用 && 和 || 需要多对方括号if [ $Name == "Steve" ] && [ $Age -eq 15 ]thenecho "This will run if $Name is Steve AND $Age is 15."fiif [ $Name == "Daniya" ] || [ $Name == "Zach" ]thenecho "This will run if $Name is Daniya OR Zach."fi

a="abc"b="efg"if [ -z $a ]then...fi
文件测试运算符用于检测 Unix 文件的各种属性。依赖文件 path 字符串。
file="./test.sh"if [ -r $file ]thenecho "File has read access"elseecho "File does not have read access"fi

xx 分钟系列:
手册系列: