Shell既是一种命令语言,有是一种程序设计语言.
它可以交互解释用户输入的命令,也可以有各种变量,参数,控制结构.
类型
几种常见类型的shell
- bash:是Linux标准默认的shell
- sh:是Unix标准默认的shell(包括macox)
简单例子
test.sh1
2#!/bin/bash
echo "Hello World"
chmod +x ./test.sh #使脚本具有执行权限
./test.sh #执行脚本
sh test.sh #执行脚本
这里要写成./test.sh,而不是test.sh,如果这样写,linux系统回去path中寻找有没有test.sh
学习
read关键字
read可以从stdin获取输入的赋值并且赋值到一个变量1
2
3echo "What is your name?"
read PERSON
echo "Hello, $PERSON"
变量
定义变量
vareName=”value”
变量名和等号之间不能有空格
使用变量
1 | varName="a value" |
使用一个定义过的变量,只要在前面加$访问即可
也可以用{}扩住变量,方便让解释器识别变量的边界,推荐使用
用readonly关键字可以定义只读变量
用unset关键字可以删除变量
特殊的变量
- $0 当前脚本的文件名
- $n 传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是$1,第二个参数是$2。
- $# 传递给脚本或函数的参数个数。
- $* 传递给脚本或函数的所有参数。
- $@ 传递给脚本或函数的所有参数。被双引号(“ “)包含时,与 $* 稍有不同
- $? 上个命令的退出状态,或函数的返回值。大部分成功返回0,失败返回1.
- $$ 当前Shell进程ID。对于 Shell 脚本,就是这些脚本所在的进程ID。
$* 和 $@ 的区别
感觉不是很常用的东西,但是还是从学习网站中摘录出来,以备不时之需
$* 和 $@ 都表示传递给函数或脚本的所有参数,不被双引号(“ “)包含时,都以”$1” “$2” … “$n” 的形式输出所有参数。
但是当它们被双引号(“ “)包含时,”$*” 会将所有的参数作为一个整体,以”$1 $2 … $n”的形式输出所有参数;”$@”会将各个参数分开,以”$1” “$2” … “$n” 的形式输出所有参数。
-e 如果echo中有转义符,需要加-e1
2
3#!/bin/bash
a=10
echo -e "Value of a is $a \n"
命令替换
命令替换是指Shell可以先执行命令,将输出结果暂时保存,在适当的地方输出。
1 | `command` |
一个简单的例子
1 | #!/bin/bash |
变量替换
根据变量的状态(是否为空,是否定义)来改变它的值
形式 | 说明 |
---|---|
${var} | 变量本来的值 |
${var:-word} | 如果变量 var 为空或已被删除(unset),那么返回 word,但不改变 var 的值 |
${var:=word} | 如果变量 var 为空或已被删除(unset),那么返回 word,并将 var 的值设置为 word。 |
${var:?message} | 如果变量 var 为空或已被删除(unset),那么将消息 message 送到标准错误输出,可以用来检测变量 var是否可以被正常赋值。若此替换出现在Shell脚本中,那么脚本将停止运行。 |
${var:+word} | 如果变量 var 被定义,那么返回 word,但不改变 var 的值。 |
运算
Bash 支持很多运算符,包括算数运算符、关系运算符、布尔运算符、字符串运算符和文件测试运算符。
原生bash不支持简单的数学运算,但是可以通过其他命令来实现,例如 awk 和 expr,expr 最常用。
例如:两个数相加:
1 | #!/bin/bash |
注意:
- 表达式和运算符之间要有空格,例如 2+2 是不对的,必须写成 2 + 2,这与我们熟悉的大多数编程语言不一样。
- 完整的表达式要被
算术运算符
1 | #!/bin/sh |
注意条件表达式的空格,[ $a == $b ],错误写法:[$a==$b]
关系运算符
关系运算符只支持数字,不支持字符串,除非字符串是数字
运算符 | 说明 | 举例 |
---|---|---|
-eq | 检测两个数是否相等,相等返回 true。 | [ $a -eq $b ] 返回 true |
-ne | 检测两个数是否相等,不相等返回 true。 | [ $a -ne $b ] 返回 true。 |
-gt | 检测左边的数是否大于右边的,如果是,则返回 true。 | [ $a -gt $b ] 返回 false。 |
-lt | 检测左边的数是否小于右边的,如果是,则返回 true。 | [ $a -lt $b ] 返回 true。 |
-ge | 检测左边的数是否大等于右边的,如果是,则返回 true。 | [ $a -ge $b ] 返回 false。 |
-le | 检测左边的数是否小于等于右边的,如果是,则返回 true。 | [ $a -le $b ] 返回 true。 |
布尔运算符
运算符 | 说明 | 举例 |
---|---|---|
! | 非运算,表达式为 true 则返回 false,否则返回 true。 | [ ! false ] 返回 true。 |
-o | 或运算,有一个表达式为 true 则返回 true。 | [ $a -lt 20 -o $b -gt 100 ] 返回 true。 |
-a | 与运算,两个表达式都为 true 才返回 true。 | [ $a -lt 20 -a $b -gt 100 ] 返回 false。 |
字符串运算符
运算符 | 说明 | 举例 |
---|---|---|
= | 检测两个字符串是否相等,相等返回 true。 | [ $a = $b ] 返回 false。 |
!= | 检测两个字符串是否相等,不相等返回 true。 | [ $a != $b ] 返回 true。 |
-z | 检测字符串长度是否为0,为0返回 true。 | [ -z $a ] 返回 false。 |
-n | 检测字符串长度是否为0,不为0返回 true。 | [ -z $a ] 返回 true。 |
str | 检测字符串是否为空,不为空返回 true。 | [ $a ] 返回 true。 |
文件测试运算符
操作符 | 说明 | 举例 |
---|---|---|
-b | file 检测文件是否是块设备文件,如果是,则返回 true。 | [ -b $|file ] 返回 false。 |
-c | file 检测文件是否是字符设备文件,如果是,则返回 true。 | [ -b $|file ] 返回 false。 |
-d | file 检测文件是否是目录,如果是,则返回 true。 | [ -d $|file ] 返回 false。 |
-f | file 检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true。 | [ -f $|file ] 返回 true。 |
-g | file 检测文件是否设置了 SGID 位,如果是,则返回 true。 | [ -g $|file ] 返回 false。 |
-k | file 检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true。 | [ -k $|file ] 返回 false。 |
-p | file 检测文件是否是具名管道,如果是,则返回 true。 | [ -p $|file ] 返回 false。 |
-u | file 检测文件是否设置了 SUID 位,如果是,则返回 true。 | [ -u $|file ] 返回 false。 |
-r | file 检测文件是否可读,如果是,则返回 true。 | [ -r $|file ] 返回 true。 |
-w | file 检测文件是否可写,如果是,则返回 true。 | [ -w $|file ] 返回 true。 |
-x | file 检测文件是否可执行,如果是,则返回 true。 | [ -x $|file ] 返回 true。 |
-s | file 检测文件是否为空(文件大小是否大于0),不为空返回 true。 | [ -s $|file ] 返回 true。 |
-e | file 检测文件(包括目录)是否存在,如果是,则返回 true。 | [ -e $|file ] 返回 true。 |
字符串
字符串拼接
1 | #!/bin/sh |
获取字符串的长度
1 | string="abcd" |
提前字符串
1 | string="alibaba is a great company" |
查找子字符串
1 | string="alibaba is a great company" |
查找字符串中的s的位置(位置是10),这个在linux下可以,mac下不可以
数组
bash只支持一维数组,获取数组元素用下标,从0开始,可以是整数或者算术表达式
定义数组
用括号表示数组,用空格分割
array_name=(value0 value1 value2 value3)
或者
array_name=(
value0
value1
value2
value3
)
也可以单独定义
array_name[0]=value0
array_name[1]=value1
array_name[2]=value2
读取数组
${array_name[index]}
eg:
valuen=${array_name[2]}
使用@ 或 * 可以获取数组中的所有元素,例如:
${array_name[*]}
${array_name[@]}
eg
1 | #!/bin/sh |
数组长度的获取
1 | # 取得数组元素的个数 |
printf
echo是简单的输出,shell的一个内部指令(双引号可有可无,单引号用于原样输出,eg:`date`)
printf用于格式化输出.
printf 命令的语法:
printf format-string [arguments...]
format-string 为格式控制字符串,arguments 为参数列表。
注意事项
- printf 命令不用加括号
- format-string 可以没有引号,但最好加上,单引号双引号均可。
- 参数多于格式控制符(%)时,format-string 可以重用,可以将所有参数都转换。
- arguments 使用空格分隔,不用逗号。
1 | # format-string为双引号 |
if
- if … fi 语句;
- if … else … fi 语句;
- if … elif … else … fi 语句。
基本格式
if [ expression ]
then
Statement(s) to be executed if expression is true
fi
case
case 值 in
模式1)
command1
command2
command3
;;
模式2)
command1
command2
command3
;;
*)
command1
command2
command3
;;
esac
case工作方式如上所示。取值后面必须为关键字 in,每一模式必须以右括号结束。取值可以为变量或常数。匹配发现取值符合某一模式后,其间所有命令开始执行直至 ;;。;; 与其他语言中的 break 类似,意思是跳到整个 case 语句的最后。
eg:
1 | echo 'Input a number between 1 to 4' |
再来一个例子,很多时候我们在bash中会带参数使用(eg:cocos run -p android -m release)
1 | #!/bin/bash |
运行时候:
$./test.sh
test.sh: usage: [ -f filename ] | [ -d directory ]
$ ./test.sh -f index.htm
File name is index.htm
$ ./test.sh -d unix
Dir name is unix
for循环
格式:
for 变量 in 列表
do
command1
command2
...
commandN
done
列表是一组值(1.数字 2.字符串 每个值通过空格分割 )
eg1:
1 | for loop in 1 2 3 4 5 |
eg2:
1 | for str in 'This is a string' |
eg3:
1 | #!/bin/bash |
输出结果:
/Users/killer/.bash_history
/Users/killer/.bash_profile
/Users/killer/.bash_sessions
/Users/killer/.bashrc
解释:$HOME 当前登录用户的宿主目录,如果是root用户就是/root, 如果是user就是/home/登录名
while
语法:
1 | while command |
eg
1 | COUNTER=0 |
util
语法:
1 | until command |
command 一般为条件表达式,如果返回值为 false,则继续执行循环体内的语句,否则跳出循环。
break和continue
break:
在嵌套循环中,break 命令后面还可以跟一个整数,表示跳出第几层循环。例如:
break n
eg1:
1 | #!/bin/bash |
eg2:
1 | #!/bin/bash |
continue
continue命令后面也可以跟一个整数,表示跳出几层
eg:
1 | #!/bin/bash |
输出结果:
this number is 2 5
this number is 2 6
this number is 4 5
this number is 4 6
解释:当var1为偶数的时候,如果第二个参数大于5(就是6),真心continue 2,直接跳出两重循环
函数
shell的函数必须先定义后使用
Shell 函数的定义格式如下:
function_name () {
list of commands
[ return value ]
}
如果你愿意,也可以在函数名前加上关键字 function(我在mac和linux下测试无效):
function function_name () {
list of commands
[ return value ]
}
函数返回值,可以显式增加return语句;如果不加,会将最后一条命令运行结果作为返回值。
Shell 函数返回值只能是整数,一般用来表示函数执行成功与否,0表示成功,其他值表示失败。如果 return 其他数据,比如一个字符串,往往会得到错误提示:“numeric argument required”。
如果一定要让函数返回字符串,那么可以先定义一个变量,用来接收函数的计算结果,脚本在需要的时候访问这个变量来获得函数返回值。
函数调用的时候不用加括号
eg:带return的用法
1 | #!/bin/bash |
注意:函数的返回值在调用该函数后通过$?来获取
$(($a1+$a2))如果不这样写,会被当成字符串,也可以这样写:expr $a1 + $a2
像删除变量一样,函数也可以删除,unset 带上.f选项(-f好像也可以)
$unset .f function_name
shell函数的参数:
注意,$10 不能获取第十个参数,获取第十个参数需要${10}。当n>=10时,需要使用${n}来获取参数。
输出重定向
基本语法:
$ command > file
如果不希望文件内容被覆盖,可以使用 >> 追加到文件末尾,例如:
输入重定向:
command < file
文件包含
a.sh:1
url="http://3toptop.top"
b.sh:1
2
3#!/bin/bash
. ./a.sh
echo $url
执行:1
2chmod +x b.sh
./b.sh
shell通配符(wildcard )
运算符 | 含义 | 实例 |
---|---|---|
* | 匹配 0 或多个字符 | [ $a -eq $b ] a*b a与b之间可以有任意长度的任意字符, 也可以一个也没有, 如aabcb, axyzb, a012b, ab。 |
? | 匹配任意一个字符 | [ $a -ne $b ] a?b a与b之间必须也只能有一个字符, 可以是任意字符, 如aab, abb, acb, a0b。。 |
[list] | 匹配 list 中的任意单一字符 | [ $a -gt $b ] a[xyz]b a与b之间必须也只能有一个字符, 但只能是 x 或 y 或 z, 如: axb, ayb, azb。 |
[!list] | 匹配 除list 中的任意单一字符 | [ $a -lt $b ] a[!0-9]b a与b之间必须也只能有一个字符, 但不能是阿拉伯数字, 如axb, aab, a-b。 |
[c1-c2] | 匹配 c1-c2 中的任意单一字符 如:[0-9] [a-z] | [ $a -ge $b ] a[0-9]b 0与9之间必须也只能有一个字符 如a0b, a1b… a9b。 |
{string1,string2,…} | 匹配 sring1 或 string2 (或更多)其一字符串 | a{abc,xyz,123}b a与b之间只能是abc或xyz或123这三个字符串之一。 |
参考文档:C语言中文网