tips
ps:下文中,我们使用$ 表示终端提示符表示输入命令的符号,- 表示多行命令的换行(多行命令不挤在一行以便美观),> 表示终端的输出。
右侧边有导航栏,可进行跳转
- shell脚本通常以shebang起始,/bin/bash是Bash的解释器命令路径
#!/bin/bash
执行脚本
fork模式
我们所执行的任何程序,都是由父进程(parent process)所产生出来的一个子进程(child process),子进程在结束后,将返回到父进程去。此一现像在Linux系统中被称为 fork。当子进程被产生的时候,将会从父进程那里获得一定的资源分配、及(更重要的是)继承父进程的环境。
fork模式,脚本的执行方式有两种。
source模式,脚本的执行方式有两种。
source命令+文件路径
$ source myScript.sh 或 source ./myScript.sh
. 命令
$ . myScript.sh 或 . ./myScript.sh
exec模式
exec模式和source方式一样,不另外创建子进程,而是在当前的的Shell环境中执行脚本,但是执行完后会终止当前的shell进程,如果使用终端,可以看见执行exec后终端退出。
exec命令
exec ./mytest.sh 或 exec myScript.sh
配置文件
你在命令行中输入的绝大部分命令都可以放置在一个特殊的文件中,留待登录或启动新的bash会话时执行。将函数定义、别名以及环境变量设置放置在这种特殊文件中,是一种定制shell的常用方法。
- 当用户登录shell时,会执行下列文件:
- /etc/profile
- $HOME/.profile
- $HOME/.bash_login
- $HOME/.bash_profile
注意,如果你是通过图形化登录管理器登入的话,是不会执行/etc/profile、$HOME/.profile和$HOME/.bash_profile这3个文件的。这是因为图形化窗口管理器并不会启动shell。当你打开终端窗口时才会创建shell,但这个shell也不是登录shell。
如果.bash_profile或.bash_login文件存在,则不会去读取.profile文件。
- 交互式shell(如X11终端会话)或ssh执行单条命令(如ssh 192.168.1.1 ls /tmp)时,
会读取并执行以下文件:- /etc/bash.bashrc
- $HOME/.bashrc
- 调用ssh登录会话
ssh 192.168.1.100
这会创建一个新的登录bash shell,该shell会读取并执行以下文件:- /etc/profile
- /etc/bash.bashrc
- $HOME/.profile
- .bashrc_profile
- 运行脚本 不会执行任何配置文件,除非定义了环境变量BASH_ENV:
1
2
3
4//如果运行如下脚本:
$> cat myscript.sh
#!/bin/bash
echo "Running"1
2$> export BASH_ENV=~/.bashrc
$> ./myscript.sh变量
Shell变量大致可以分为3种类型:
内部变量:系统提供,不用定义,不能修改,比如$#,$?,$*,$0等
环境变量:系统提供,不用定义,可以修改,当前进程及其子进程中使用,比如PATH,PWD,SHELL等
用户变量(本地变量):用户定义,可以修改,在当前进程使用,比如var=123等
定义变量
定义变量有如下几种形式
- 不加符号的等号操作符赋值
varName=value
如果value不包含任何空白字符(例如空格),那么就不需要将其放入引号中,否则必须使用单引号或双引号。
- 单引号的等号操作符赋值
1
2
3
4//单引号不扩展或解释任何变量和符号
$ test='ps$?'
$ echo $test
> ps$? - 双引号的等号操作符赋值
1
2
3
4//双引号会扩展解释变量和符号,其中$?为上条命令执行的结果
$ test="ps$?"
$ echo $test
> ps0 - 反引号的等号操作符赋值
1
2
3
4//反引号(键盘上的~键),将内容命令的输出存入变量,该例中将ps命令的输出存入test
$ test=`ps`
$ echo $test
PID TTY TIME CMD 2856 pts/0 00:00:00 bash 3234 pts/0 00:00:00 ps - 子shell的等号操作符赋值
1
2
3
4//使用$(),将开启子shell,或者说子进程执行内容命令,并将内容命令的输出存入变量,该例中将ps命令的输出存入test
$ test=$(ps)
$ echo $test
PID TTY TIME CMD 2856 pts/0 00:00:00 bash 3234 pts/0 00:00:00 ps注意,var = value不同于var=value。两边没有空格的等号是赋值操作符,加上空格的等号表示的是等量关系测试。
- export命令
1
2
3
4HTTP_PROXY=192.168.1.23:3128
export HTTP_PROXY
//export命令声明了将由子进程所继承的一个或多个变量。
//这些变量被导出后,当前shell脚本所执行的任何应用程序都会获得这个变量。如果需要append变量,例如对PATH中添加一条新路径,可以使用如下命令:
export PATH 1
2### 常见的环境变量
- SHELL:环境变量SHELL获知当前使用的是哪种shell$ echo $SHELL
$ echo $0
/bin/bash$ oldIFS=$IFS1
2
3
4
5- UID:环境变量UID中保存的是用户ID。root用户的UID是0。
- PS1:当我们打开终端或是运行shell时,会看到类似于user@hostname:/home/$ 的提示字符串。不同的GNU/Linux发布版中的提示字符串及颜色各不相同。我们可以利用PS1环境变量来定义主提示字符串。
- PATH:PATH环境变量通常保存了可用于搜索可执行文件的路径列表。`PATH=/usr/bin; /bin`这意味着只要shell执行应用程序(二进制文件或脚本)时,它就会首先查找/usr/bin,然后查找/bin。
- LD_LIBRARY_PATH:LD_LIBRARY_PATH环境变量通常保存了可用于搜索库文件的路径列表。`LD_LIBRARY_PATH=/usr/lib; /lib`这意味着只要shell执行库文件时,它就会首先查找/usr/lib,然后查找/lib。
- IFS:内部字段分隔符(internal field separator)。IFS环境变量保存了用于分隔的字符。它是当前shell环境使用的默认定界字符串。IFS的默认值为空白字符(换行符、制表符或者空格)。 - IFS=, #IFS现在被设置为,
- for item in $data;
- do
- echo Item: $item
- done
- IFS=$oldIFS
Item: name
Item: gender
Item: rollno
Item: location1
2
3- SHLVL:保存当前shell的层级
### 访问变量
- 和编译型语言不同,大多数脚本语言不要求在创建变量之前声明其类型。用到什么类型就是什么类型。在变量名前面加上一个美元符号就可以访问到变量的值。也可以使用${var}。其分别如下:$ fruit=apple
$ count=5
$ echo “We have $count ${fruit}s”We have 5 apples
//因为shell使用空白字符来分隔单词,
//所以我们需要加上一对花括号来告诉shell这里的变量名是fruit,
//而不是fruits。1
2### 获得字符串的长度
- 可以用下面的方法获得变量值的长度:$ var=12345678901234567890
$ echo $操作符
% %% # ## 操作符可以得到变量var删除特定的值后的结果:
假设我们定义file=/dir1/dir2/dir3/my.file.txt
可以用${ }分别替换得到不同的值:
- ${file#*/}:删掉第一个 / 及其左边的字符串:dir1/dir2/dir3/my.file.txt
- ${file##*/}:删掉最后一个 / 及其左边的字符串:my.file.txt
- ${file#*.}:删掉第一个 . 及其左边的字符串:file.txt
- ${file##*.}:删掉最后一个 . 及其左边的字符串:txt
- ${file%/*}:删掉最后一个 / 及其右边的字符串:/dir1/dir2/dir3
- ${file%%/*}:删掉第一个 / 及其右边的字符串:(空值)
- ${file%.*}:删掉最后一个 . 及其右边的字符串:/dir1/dir2/dir3/my.file
- ${file%%.*}:删掉第一个 . 及其右边的字符串:/dir1/dir2/dir3/my
记忆方法:
是去掉左边(键盘上#在 $ 的左边)去掉左边的时候,通配符*就要在指定的符号左边
% 是去掉右边(键盘上% 在$ 的右边)去掉右边的时候,通配符*就要在指定的符号右边
单一符号是最小匹配;吝啬匹配
两个符号是最大匹配;贪婪匹配
${::}操作符
- ${file:0:5} :提取从第0个开始的连续5个字节:/dir1
- ${file:5:5} :提取第5个开始的连续5个字节:/dir2
${//}
- ${file/dir/path}:将第一个dir替换为path:/path1/dir2/dir3/my.file.txt
- ${file//dir/path}:将全部dir 替换为 path:/path1/path2/path3/my.file.txt
同样的:单一符号是最小匹配;吝啬匹配
两个符号是最大匹配;贪婪匹配&&和||
- shell 在执行某个命令的时候,会返回一个返回值,该返回值保存在 shell 变量 $? 中。当 $? == 0 时,表示执行成功;当 $? == 1 时(我认为是非0的数,返回值在0-255间),表示执行失败。
- 有时候,下一条命令依赖前一条命令是否执行成功。如:在成功地执行一条命令之后再执行另一条命令,或者在一条命令执行失败后再执行另一条命令等。shell 提供了 && 和 || 来实现命令执行控制的功能,shell 将根据 && 或 || 前面命令的返回值来控制其后面命令的执行。
- 无论是&&还是||,联合命令行都会尽量执行至成功为止。(这才有了短路的意义)
1
2
3
4
5
6
7
8
9command1 && command2 [&& command3 ...]
//命令之间使用 && 连接,实现逻辑与的功能。
//只有在 && 左边的命令返回真(命令返回值 $? == 0),&& 右边的命令才会被执行。
//只要有一个命令返回假(命令返回值 $? == 1),后面的命令就不会被执行。
command1 || command2 [|| command3 ...]
//命令之间使用 || 连接,实现逻辑或的功能。
//只有在 || 左边的命令返回假(命令返回值 $? == 1),|| 右边的命令才会被执行。这和 c 语言中的逻辑或语法功能相同,即实现短路逻辑或操作。
//只要有一个命令返回真(命令返回值 $? == 0),后面的命令就不会被执行。 –直到返回真的地方停止执行。管道符 |
Unix shell脚本最棒的特性之一就是可以轻松地将多个命令组合起来生成输出。一个命令的输出可以作为另一个命令的输入,而这个命令的输出又会传递至下一个命令,以此类推。
1 | //这里我们组合了3个命令。cmd1的输出传递给cmd2,cmd2的输出传递给cmd3,最终的输出 12(来自cmd3)会出现在显示器中或被导入某个文件。 |
shell代码执行顺序
重定向执行顺序
先读取输入重定向符<后的内容做为输入,如果一条命令有多个<,会读取最后一个<后的内容
输入重定向符<放在命令前后都可以,例如【< /etc/hosts cat】相当于【cat /etc/hosts】执行命令
如果有>或>>会将结果进行重定向,如果输出重定向多个文件,只会将内容重定向到最后一个文件
例如 cat /etc/hosts > test1.txt >test2.txt,只有test2.txt会出现内容,test1.txt内容是空的
输出重定向>和>>的位置放在哪里都可以,例如【> test.txt cat /etc/hosts】,表示将/etc/hosts的内容输入到test.txt中
管道符执行顺序
command1 | command2
命令1必须要有输出,且是正确的。命令2才会执行。命令1的输出作为命令2的输入
数学运算-let、(( ))和[]
Bash shell使用let、(( ))和[]执行基本的算术操作。工具expr和bc可以用来执行高级操作。
- let命令
- let命令可以直接执行基本的算术操作。当使用let时,变量名之前不需要再添加$,例如:
1
2
3
4
5$ no1=4;
$ no2=5;
$ let result=no1
$ echo $result
> 9 - let自操作
1
2
3
4$ let no1++
$ let no1--
$ let no+=6
$ let no-=6
- let命令可以直接执行基本的算术操作。当使用let时,变量名之前不需要再添加$,例如:
- 操作符$[]和$(())
- 操作符[]的使用方法和let命令一样:
1
2
3
4
5$ result=$[ no1 + no2 ]
//在[]中也可以使用$前缀,例如:
$ result=$[ $no1 + 5 ]
//也可以使用操作符(())
$ result=$(( no1 + 50 ))
- 操作符[]的使用方法和let命令一样:
- expr
- expr同样可以用于基本算术操作
1
2$ result=`expr 3 + 4`
$ result=$(expr $no1 + 5)
- expr同样可以用于基本算术操作
- bc
- 上述命令不支持浮点数计算,浮点数计算需要使用bc命令,bc是一个用于数学运算的高级实用工具,这个精密的计算器包含了大量的选项。我们可以借助它执行浮点数运算并使用一些高级函数:
1
2
3
4
5
6$ echo "4 * 0.56" | bc
> 2.24
$ no=54;
$ result=`echo "$no * 1.5" | bc`
$ echo $result
> 81.0 - 设定小数精度。
1
2
3//在下面的例子中,参数scale=2将小数位个数设置为2。因此,bc将会输出包含两个小数位的数值:
$ echo "scale=2;22/7" | bc
> 3.14 - 进制转换
1
2
3
4
5
6
7//用bc可以将一种进制系统转换为另一种。来看看下面的代码是如何在十进制与二进制之间相互转换的:
$ no=100
$ echo "obase=2;$no" | bc
> 1100100
$ no=1100100
$ echo "obase=10;ibase=2;$no" | bc
> 100 - 计算平方以及平方根。
1
2$ echo "sqrt(100)" | bc #Square root
$ echo "10^10" | bc #Square
- 上述命令不支持浮点数计算,浮点数计算需要使用bc命令,bc是一个用于数学运算的高级实用工具,这个精密的计算器包含了大量的选项。我们可以借助它执行浮点数运算并使用一些高级函数:
文件描述符与重定向
文件描述符是与输入和输出流相关联的整数。最广为人知的文件描述符是stdin、stdout和stderr。文件描述符0、1以及2是系统预留的。
文件描述符
1
2
30 —— stdin (标准输入)。
1 —— stdout(标准输出)。
2 —— stderr(标准错误)。重定向符号
符号 说明 < file 输入重定向,将<后的file文件内容作为command执行前的输入 > file 或1>file 输出重定向,将标准正确输出覆盖到后面的file文件内 >> file或1>>file 输出重定向,将标准正确输出追加到后面的file文件内 2>file 输出重定向,将标准错误输出覆盖到后面的file文件内 2>>file 输出重定向,将标准错误输出追加到后面的file文件内 &>file 或 >file 2>&1 输出重定向,将标准正确输出和标准错误输出覆盖到后面的file文件内 &>>file 或 >>file 2>&1 输出重定向,将标准正确输出和标准错误输出追加到后面的file文件内
如果你不想看到或保存错误信息,那么可以将stderr的输出重定向到/dev/null,保证一切都
会被清除得干干净净。
cat<
log.txt,注意,<<EOF是固定用法,<<不是指输入重定向两次,命令<<EOF会将键入的、以EOF输入字符为标准输入结束的流内容作为输入。然后按照重定向执行顺序,第二步骤执行cat命令,输出<<EOF键入的内容,最后将其重定向进log.txt
数组与关联数组
数组允许脚本利用索引将数据集合保存为独立的条目。Bash支持普通数组和关联数组,前者使用整数作为数组索引,后者使用字符串作为数组索引。当数据以数字顺序组织的时候,应该使用普通数组,例如一组连续的迭代。当数据以字符串组织的时候,关联数组就派上用场了,例如主机名称。
值序列
值序列在循环中经常使用,我们可以使用{1..5}来得到1-5的数字序列,也可以使用{1,2,3,4,5}得到同样的序列,也可以用{a..z}得到a-z的集合。
1 | echo {1..5} |
普通数组
定义数组
- 可以在单行中使用数值列表来定义一个数组
1
2//这些值将会存储在以0为起始索引的连续位置上
$ array_var=(test1 test2 test3 test4) - 定义特定索引数组值
1
$ array_var[2]="test3"
- 定义空数组并加值
1
2
3$ array_var=();
//加入someVar变量值
$ array_var+=("$someVar");
- 可以在单行中使用数值列表来定义一个数组
访问数组
- 访问特定索引的数组元素内容
1
2
3
4
5$ echo ${array_var[0]}
> test1
$ index=5
$ echo ${array_var[$index]}
> test6 - 以列表形式打印出数组中的所有值
1
2
3
4
5$ echo ${array_var[*]}
> test1 test2 test3 test4 test5 test6
//或
$ echo ${array_var[@]}
> test1 test2 test3 test4 test5 test6 - 打印数组长度(即数组中元素的个数)
1
$ echo ${#array_var[*]}
关联数组
关联数组从Bash 4.0版本开始被引入。当使用字符串(站点名、用户名、非顺序数字等)作为索引时,关联数组要比数字索引数组更容易使用。
- 访问特定索引的数组元素内容
定义关联数组
在关联数组中,我们可以用任意的文本作为数组索引。首先,需要使用声明语句将一个变量定义为关联数组
1
2$ declare -A fruits_value
$ fruits_value=([apple]='100 dollars' [orange]='150 dollars')访问数组
- 用下面的方法显示数组内容
1
2$ echo "Apple costs ${fruits_value[apple]}"
> Apple costs 100 dollars - 列出数组索引(对于普通数组,这个方法同样可行。)
1
2
3
4
5$ echo ${!fruits_value[*]}
> orange apple
//或
$ echo ${!fruits_value[@]}
> orange apple
- 用下面的方法显示数组内容
函数
函数和别名乍一看很相似,不过两者在行为上还是略有不同。alias是使用纯文本代替命令名,它在命令解析阶段就会把内容进行替换,由于替换过程完全是基于文本的,因而别名可以改变shell的语法;
函数的函数体是复合命令(bash),函数名在命令解析阶段并不会被替换,只是在命令执行阶段调用相应的函数处理对应的复合命令。
函数参数可以在函数体中任意位置上使用,而别名只能将参数放在命令尾部。
定义函数
函数的定义包括function命令、函数名、开/闭括号以及包含在一对花括号中的函数体。
- function 关键字
1
2
3
4function fname()
{
statements;
} - 无 function 关键字
1
2
3
4
5
6fname()
{
statements;
}
或
fname() { statement; } - 返回值
在定义函数时,可以在函数体中使用return来定义返回值。1
2
3
4
5
6
7
8
9fname()
{
if [ $1 -eq 0 ];
then
return 0; #返回值
else
return 1; #返回值
fi
}我们知道,在使用&&和||连接符时,判断依据即为符号前后命令的成功与否,返回值等于0为成功,大于0为失败。
调用函数
1 | $ fname ; //执行函数 |
函数体中,要活用$1,$2,$*,$@等符号
递归调用
1
2
3
4fname() {
echo $1; fname hello;
sleep 1;
}自定义函数示例
自定义函数需要定义在rc或者profile文件中,此文件的作用可详见理解 bashrc 和 profile
对于
export PATH=/opt/myapp/bin:$PATH
,我们可以在.bashrc文件中定义一个新的函数,来简化这一追加路径的功能,使得export PATH=/opt/myapp/bin:$PATH
等价于prepend PATH /opt/myapp/bin
,其中$1=PATH,$2=/opt/myapp/bin:1
2
3
4
5
6
7
8prepend() { [ -d "$2" ] && eval $1=\"$2\$\{$1:+':'\$$1\}\" && export $1 ; }
// [ -d "$2" ]含义为先确认该函数第二个参数所指定的目录是否存在。
//如果存在,eval表达式将第一个参数所指定的变量值设置成第二个参数的值加上$\{$1:+':'\$$1\}表达式的值
// $1=\"$2\$\{$1:+':'\$$1\}\"
// $1="$2${PATH:+':'$PATH}" //$1=PATH有值
// $1="$2':'$PATH"
// $1="/opt/myapp/bin:$PATH"
//如果第二步执行成功,第三步,export,完成
逻辑关键字
循环-for、while、until
面向列表的for循环
list可以是一个字符串,也可以是一个值序列。
1
2
3
4for var in {1..50};
do
commands;#使用变量$var
done迭代指定范围的数字
1
2
3
4for((i=0;i<10;i++))
{
commands; #使用变量$i
}循环到条件满足为止
1
2
3
4
5
6//当条件为真时,while循环继续执行;当条件不为真时,until循环继续执行。
//用true或者:作为循环条件能够产生无限循环。
while condition
do
commands;
doneuntil循环
1
2
3
4
5
6//在Bash中还可以使用一个特殊的循环until。它会一直循环,直到给定的条件为真。例如:
x=0;
until [ $x -eq 9 ]; #条件是[$x -eq 9 ]
do
let x++; echo $x;
done判断-if else
if条件
1
2
3
4if condition;
then
commands;
fielse if和else
1
2
3
4
5
6
7
8if condition;
then
commands;
else if condition; then
commands;
else
commands;
fiif和else语句能够嵌套使用。if的条件判断部分可能会变得很长,但可以用
逻辑运算符将它变得简洁一些:
[ condition ] && action; # 如果condition为真,则执行action
[ condition ] || action; # 如果condition为假,则执行action
判断条件- [] 和 [[]]
判断条件通常被放置在封闭的中括号内。一定要注意在 [ 和 ] 与操作数之间有一个空格。如果忘记了这个空格,脚本就会报错。[$var -eq 0 ] or [ $var -eq 0]会报错
在[]和[[ ]]中,其实任何一个符号两边都要有空格,所以在判断的时候,不要吝啬空格。
对数字变量或值进行算术条件比较
1
2[ $var -eq 0 ] #当$var等于0时,返回真
[ $var -ne 0 ] #当$var不为0时,返回真其他重要的操作符如下
-gt:大于。
-lt:小于。
-ge:大于或等于。
-le:小于或等于。
这些操作符只适用于数值。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- 文件系统相关判断
我们可以使用不同的条件标志测试各种文件系统相关的属性。
- [ -f $file_var ]:如果给定的变量包含正常的文件路径或文件名,则返回真。
- [ -x $var ]:如果给定的变量包含的文件可执行,则返回真。
- [ -d $var ]:如果给定的变量包含的是目录,则返回真。
- [ -e $var ]:如果给定的变量包含的文件存在,则返回真。
- [ -c $var ]:如果给定的变量包含的是一个字符设备文件的路径,则返回真。
- [ -b $var ]:如果给定的变量包含的是一个块设备文件的路径,则返回真。
- [ -w $var ]:如果给定的变量包含的文件可写,则返回真。
- [ -r $var ]:如果给定的变量包含的文件可读,则返回真。
- [ -L $var ]:如果给定的变量包含的是一个符号链接,则返回真
- [ -s $var ]:如果给定的变量包含的文件大小大于0字节,则返回真
- [ $var1 -nt $var2 ]:new than操作,如果给定的变量包含的文件1比文件2新,则返回真
- [ $var1 -ot $var2 ]:old than操作,如果给定的变量包含的文件1比文件2旧,则返回真
- [ $var1 -ef $var2 ]:equal file操作,如果给定的变量包含的文件1和文件2为同一文件,则返回真
- 字符串比较
**进行字符串比较时,最好用双中括号**,因为有时候采用单个中括号会产生错误。
- 测试两个字符串是否相同
//当str1等于str2时,返回真。也就是说,str1和str2包含的文本是一模一样的。
[[ $str1 = $str2 ]]
//这是检查字符串是否相同的另一种写法。
[[ $str1 == $str2 ]]
//如果str1和str2不相同,则返回真。
[[ $str1 != $str2 ]]
1
2
3
4
5
> 注意在=前后各有一个空格。如果忘记加空格,那就不是比较关系了,而是变成了赋值语句。
- 字符串比较
字符串是依据字符的ASCII值进行比较的。例如,A的值是0x41,a的值是0x61。因此,A
小于a,AAa小于Aaa。
//如果str1的字母序比str2大,则返回真。
[[ $str1 > $str2 ]]
//如果str1的字母序比str2小,则返回真。
[[ $str1 < $str2 ]]
1
- 判断空串
[[ -z $str1 ]] //如果str1为空串,则返回真。
[[ ! -z $str1 ]] //如果str1为空串,则返回假。与-n 等价
[[ -n $str1 ] //如果str1不为空串,则返回真。
1
2
3
4
5
- 逻辑与和逻辑或
- -a是逻辑与操作符,-o是逻辑或操作符。可以按照下面的方法结合多个条件进行
[ $var1 -ne 0 -a $var2 -gt 2 ] #使用逻辑与-a
[ $var1 -ne 0 -o $var2 -gt 2 ] #逻辑或-o
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
- [] 和 [[ ]]的区别
二者基本相等,除了下述几点
- 逻辑运算符不同
- []使用 -a 和 -o 来表达 与 和 或,不识别&& 和 ||
- [[ ]]使用 && 和 || 来表达 与 和 或,不识别-a 和 -o
- ==含义不同
- 在[[ ]]中,表达式"=="和"!="的右边其实会被当做pattern匹配,只不过不是正则匹配,是通配符匹配(即?表示匹配单个字符,*表示匹配零个一个或多个字符)。
- [[ ]]支持正则匹配
- 在[[ ]]中,表达式"=~"的右边会被当做正则匹配
- 不过要注意,使用"=~"时,右边表达式不需要引号,如:[[ '$var' =~ a* ]]
> 使用建议,无论是[]还是[[ ]],都建议对其变量使用双引号包围,换句话说,能做字符比较的时候,不要做数值比较。例如`var='shell script' [ $var = "shell script" ]` 会报错,因为变量不加双引号,相当于[ shell script = "shell script" ],这显然是错误的,所以应该加上引号`[ "$var" = "shell script" ]`
> 使用建议,使用-eq数值比较的时候,可以在操作符两边同时+0,避免变量为空报错,当日,一边为常数的话可以不用+0:` [ $((a+0)) -le 1]`
> test命令可以用来测试条件。用test可以避免使用过多的括号,增强代码的可读性。[]中的测试条件同样可以用于test命令。`if [ $var -eq 0 ]; then echo "True"; fi` 等价于 `if test $var -eq 0 ; then echo "True"; fi`
---
## Linux/unix文件系统
### 文件权限
文件权限和所有权是Unix/Linux文件系统的显著特性之一。这些特性能够在多用户环境中保护你的个人信息。每一个文件都拥有多种类型的权限。在这些权限中,我们通常要和三组权限打交道:用户、用户组以及其他用户。
用户(user)是文件的所有者,通常拥有所有的访问权。用户组(group)是多个用户的集合(由系统管理员指定),可能拥有文件的部分访问权。其他用户(others)是除文件所有者或用户组成员之外的任何人。
ls命令的-l选项可以显示出包括文件类型、权限、所有者以及组在内的多方面信息:
$ ls -l
-rw-r–r– 1 slynux users 2497 2010-02-28 11:22 bot.py
drwxr-xr-x 2 slynux users 4096 2010-05-27 14:31 a.py
-rw-r–r– 1 slynux users 539 2010-02-10 09:11 cl.pl
1 | 上述代码中,第1列表明了文件类型。字符串slynux users分别对应用户和用户组。在这里,slynux是文件所有者,也是组成员之一。 |
//定义如下函数:
repeat()
{
while true
do
$@ && return
done
}
//函数repeat()中包含了一个无限while循环,该循环执行以函数参数形式(通过$@访问)传入的命令。如果命令执行成功,则返回,进而退出循环。
1 | 在大多数现代系统中,true是作为/bin中的一个二进制文件来实现的。 |
repeat() { while :; do $@ && return; done }
1 | 加入延时 |
//每30秒才会运行一次
repeat() { while :; do $@ && return; sleep 30; done }
---