阅读目录
1. Shell简介
Shell本身是一个用C语言编写的程序,它是用户使用Unix/Linux的桥梁,用户的大部分工作都是通过Shell完成的。Shell既是一种命令语言,又是一种程序设计语言。作为命令语言,它交互式地解释和执行用户输入的命令;作为程序设计语言,它定义了各种变量和参数,并提供了许多在高级语言中才具有的控制结构,包括循环和分支。
它虽然不是Unix/Linux系统内核的一部分,但它调用了系统核心的大部分功能来执行程序、建立文件并以并行的方式协调各个程序的运行。因此,对于用户来说,shell是最重要的实用程序,深入了解和熟练掌握shell的特性极其使用方法,是用好Unix/Linux系统的关键。
可以说,shell使用的熟练程度反映了用户对Unix/Linux使用的熟练程度。
注意:单独地学习 Shell 是没有意义的,请先参考,了解 Unix/Linux 基础。
Shell有两种执行命令的方式:
交互式(Interactive):解释执行用户的命令,用户输入一条命令,Shell就解释执行一条。
批处理(Batch):用户事先写一个Shell脚本(Script),其中有很多条命令,让Shell一次把这些命令执行完,而不必一条一条地敲命令。
Shell脚本和编程语言很相似,也有变量和流程控制语句,但Shell脚本是解释执行的,不需要编译,Shell程序从脚本中一行一行读取并执行这些命令,相当于一个用户把脚本中的命令一行一行敲到Shell提示符下执行。
Shell初学者请注意,在平常应用中,建议不要用 root 帐号运行 Shell 。作为普通用户,不管您有意还是无意,都无法破坏系统;但如果是 root,那就不同了,只要敲几个字母,就可能导致灾难性后果。
2. 几种常见的Shell
bash:bash是Linux标准默认的shell,本教程也基于bash讲解。bash由Brian Fox和Chet Ramey共同完成,是BourneAgain Shell的缩写,内部命令一共有40个。
Linux使用它作为默认的shell是因为它有诸如以下的特色:
-
可以使用类似DOS下面的doskey的功能,用方向键查阅和快速输入并修改命令。
-
自动通过查找匹配的方式给出以某字符串开头的命令。
-
包含了自身的帮助功能,你只要在提示符下面键入help就可以得到相关的帮助。
sh:sh 由Steve Bourne开发,是Bourne Shell的缩写,sh 是Unix 标准默认的shell。
ash:ash shell 是由Kenneth Almquist编写的,Linux中占用系统资源最少的一个小shell,它只包含24个内部命令,因而使用起来很不方便。
csh:csh 是Linux比较大的内核,它由以William Joy为代表的共计47位作者编成,共有52个内部命令。该shell其实是指向/bin/tcsh这样的一个shell,也就是说,csh其实就是tcsh。
ksh:ksh 是Korn shell的缩写,由Eric Gisin编写,共有42条内部命令。该shell最大的优点是几乎和商业发行版的ksh完全兼容,这样就可以在不用花钱购买商业版本的情况下尝试商业版本的性能了。
注意:bash是 Bourne Again Shell 的缩写,是linux标准的默认shell ,它基于Bourne shell,吸收了C shell和Korn shell的一些特性。bash完全兼容sh,也就是说,用sh写的脚本可以不加修改的在bash中执行。3. 编译型语言和解释型语言的区别
编译型语言
很多传统的程序设计语言,例如Fortran、Ada、Pascal、C、C++和Java,都是编译型语言。这类语言需要预先将我们写好的源代码(source code)转换成目标代码(object code),这个过程被称作“编译”。解释型语言
解释型语言也被称作“脚本语言”。执行这类程序时,解释器(interpreter)需要读取我们编写的源代码(source code),并将其转换成目标代码(object code),再由计算机运行。因为每次执行程序都多了编译的过程,因此效率有所下降。 使用脚本编程语言的好处是,它们多半运行在比编译型语言还高的层级,能够轻易处理文件与目录之类的对象;缺点是它们的效率通常不如编译型语言。不过权衡之下,通常使用脚本编程还是值得的:花一个小时写成的简单脚本,同样的功能用C或C++来编写实现,可能需要两天,而且一般来说,脚本执行的速度已经够快了,快到足以让人忽略它性能上的问题。脚本编程语言的例子有awk、Perl、Python、Ruby与Shell。4. 什么时候使用Shell?
- 简单性:Shell是一个高级语言;通过它,你可以简洁地表达复杂的操作。
- 可移植性:使用POSIX所定义的功能,可以做到脚本无须修改就可在不同的系统上执行。
- 开发容易:可以在短时间内完成一个功能强大又妤用的脚本。
- 资源密集型的任务,尤其在需要考虑效率时(比如,排序,hash等等)。
- 需要处理大任务的数学操作,尤其是浮点运算,精确运算,或者复杂的算术运算(这种情况一般使用C++或FORTRAN 来处理)。
- 有跨平台(操作系统)移植需求(一般使用C 或Java)。
- 复杂的应用,在必须使用结构化编程的时候(需要变量的类型检查,函数原型,等等)。
- 对于影响系统全局性的关键任务应用。
- 对于安全有很高要求的任务,比如你需要一个健壮的系统来防止入侵、破解、恶意破坏等等。
- 项目由连串的依赖的各个部分组成。
- 需要大规模的文件操作。
- 需要多维数组的支持。
- 需要数据结构的支持,比如链表或数等数据结构。
- 需要产生或操作图形化界面 GUI。
- 需要直接操作系统硬件。
- 需要 I/O 或socket 接口。
- 需要使用库或者遗留下来的老代码的接口。
- 私人的、闭源的应用(shell 脚本把代码就放在文本文件中,全世界都能看到)。
5. 第一个Shell脚本
#!/bin/bashecho "Hello World !"
5.1 作为可执行程序
将上面的代码保存为test.sh,并 cd 到相应目录:
chmod +x ./test.sh #使脚本具有执行权限./test.sh #执行脚本
5.2 作为解释器参数
这种运行方式是,直接运行解释器,其参数就是shell脚本的文件名,如:/bin/sh test.sh/bin/php test.php
#!/bin/bash# Author : mozhiyan# Copyright (c) http://see.xidian.edu.cn/cpp/linux/# Script follows here:echo "What is your name?"read PERSONecho "Hello, $PERSON"
chmod +x ./test.sh$./test.shWhat is your name?mozhiyanHello, mozhiyan
6. Shell变量
6.1 定义变量
定义变量时,变量名不加美元符号($),如:variableName="value"
- 首个字符必须为字母(a-z,A-Z)。
- 中间不能有空格,可以使用下划线(_)。
- 不能使用标点符号。
- 不能使用bash里的关键字(可用help命令查看保留关键字)。
myUrl="http://see.xidian.edu.cn/cpp/linux/"myNum=100
6.2 使用变量
使用一个定义过的变量,只要在变量名前面加美元符号($)即可,如:your_name="mozhiyan"echo $your_nameecho ${your_name}
for skill in Ada Coffe Action Javadoecho "I am good at ${skill}Script"done
6.3 重新定义变量
已定义的变量,可以被重新定义,如:myUrl="http://see.xidian.edu.cn/cpp/linux/"echo ${myUrl}myUrl="http://see.xidian.edu.cn/cpp/shell/"echo ${myUrl}
6.4 只读变量
使用 readonly 命令可以将变量定义为只读变量,只读变量的值不能被改变。 下面的例子尝试更改只读变量,结果报错:#!/bin/bashmyUrl="http://see.xidian.edu.cn/cpp/shell/"readonly myUrlmyUrl="http://see.xidian.edu.cn/cpp/danpianji/"
/bin/sh: NAME: This variable is read only.
6.5 删除变量
使用 unset 命令可以删除变量。语法:unset variable_name
#!/bin/shmyUrl="http://see.xidian.edu.cn/cpp/u/xitong/"unset myUrlecho $myUrl
6.6 变量类型
运行shell时,会同时存在三种变量:1) 局部变量
局部变量在脚本或命令中定义,仅在当前shell实例中有效,其他shell启动的程序不能访问局部变量。2) 环境变量
所有的程序,包括shell启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行。必要的时候shell脚本也可以定义环境变量。3) shell变量
shell变量是由shell程序设置的特殊变量。shell变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了shell的正常运行7.Shell特殊变量
$echo $$
变量 | 含义 |
---|---|
$0 | 当前脚本的文件名 |
$n | 传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是1,第二个参数是1,第二个参数是2。 |
$# | 传递给脚本或函数的参数个数。 |
$* | 传递给脚本或函数的所有参数。 |
$@ | 传递给脚本或函数的所有参数。被双引号(" ")包含时,与 $* 稍有不同,下面将会讲到。 |
$? | 上个命令的退出状态,或函数的返回值。 |
$$ | 当前Shell进程ID。对于 Shell 脚本,就是这些脚本所在的进程ID。 |
命令行参数
运行脚本时传递给脚本的参数称为命令行参数。命令行参数用 n表示,例如,n表示,例如,1 表示第一个参数,$2 表示第二个参数,依次类推。 请看下面的脚本:#!/bin/bashecho "File Name: $0"echo "First Parameter : $1"echo "First Parameter : $2"echo "Quoted Values: $@"echo "Quoted Values: $*"echo "Total Number of Parameters : $#"
$./test.sh Zara AliFile Name : ./test.shFirst Parameter : ZaraSecond Parameter : AliQuoted Values: Zara AliQuoted Values: Zara AliTotal Number of Parameters : 2
∗和∗和@ 的区别
∗和∗和@ 都表示传递给函数或脚本的所有参数,不被双引号(" ")包含时,都以"1""1""2" … "$n" 的形式输出所有参数。 但是当它们被双引号(" ")包含时,"∗"会将所有的参数作为一个整体,以"∗"会将所有的参数作为一个整体,以"1 2…2…n"的形式输出所有参数;"@"会将各个参数分开,以"@"会将各个参数分开,以"1" "2"…"2"…"n" 的形式输出所有参数。 下面的例子可以清楚的看到 ∗和∗和@ 的区别:#!/bin/bashecho "\$*=" $*echo "\"\$*\"=" "$*"echo "\$@=" $@echo "\"\$@\"=" "$@"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
$*= a b c d"$*"= a b c d$@= a b c d"$@"= a b c dprint each param from $*abcdprint each param from $@abcdprint each param from "$*"a b c dprint each param from "$@"abcd
退出状态
$? 可以获取上一个命令的退出状态。所谓退出状态,就是上一个命令执行后的返回结果。 退出状态是一个数字,一般情况下,大部分命令执行成功会返回 0,失败返回 1。 不过,也有一些命令返回其他值,表示不同类型的错误。 下面例子中,命令成功执行:$./test.sh Zara AliFile Name : ./test.shFirst Parameter : ZaraSecond Parameter : AliQuoted Values: Zara AliQuoted Values: Zara AliTotal Number of Parameters : 2$echo $?0$
8. Shell替换
#!/bin/basha=10echo -e "Value of a is $a \n"
Value of a is 10
Value of a is 10\n
转义字符 | 含义 |
---|---|
\\ | 反斜杠 |
\a | 警报,响铃 |
\b | 退格(删除键) |
\f | 换页(FF),将当前位置移到下页开头 |
\n | 换行 |
\r | 回车 |
\t | 水平制表符(tab键) |
\v | 垂直制表符 |
命令替换
命令替换是指Shell可以先执行命令,将输出结果暂时保存,在适当的地方输出。 命令替换的语法:`command`
#!/bin/bashDATE=`date`echo "Date is $DATE"USERS=`who | wc -l`echo "Logged in user are $USERS"UP=`date ; uptime`echo "Uptime is $UP"
Date is Thu Jul 2 03:59:57 MST 2009Logged in user are 1Uptime is Thu Jul 2 03:59:57 MST 200903:59:57 up 20 days, 14:03, 1 user, load avg: 0.13, 0.07, 0.15
变量替换
变量替换可以根据变量的状态(是否为空、是否定义等)来改变它的值。 可以使用的变量替换形式:形式 | 说明 |
---|---|
${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 的值。 |
#!/bin/bashecho ${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 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 set1 - Value of var isVariable is not set2 - Value of var is Variable is not set3 - Value of var isThis is default value4 - Value of var is PrefixPrefix5 - Value of var is Prefix
9. Shell运算符
#!/bin/bashval=`expr 2 + 2`echo "Total value : $val"
Total value : 4
- 表达式和运算符之间要有空格,例如 2+2 是不对的,必须写成 2 + 2,这与我们熟悉的大多数编程语言不一样。
- 完整的表达式要被 ` ` 包含,注意这个字符不是常用的单引号,在 Esc 键下边。
9.1 算术运算符
先来看一个使用算术运算符的例子:#!/bin/sha=10b=20val=`expr $a + $b`echo "a + b : $val"val=`expr $a - $b`echo "a - b : $val"val=`expr $a \* $b`echo "a * b : $val"val=`expr $b / $a`echo "b / a : $val"val=`expr $b % $a`echo "b % a : $val"if [ $a == $b ]thenecho "a is equal to b"fiif [ $a != $b ]thenecho "a is not equal to b"fi
a + b : 30a - b : -10a * b : 200b / a : 2b % a : 0a is not equal to b
- 乘号(*)前边必须加反斜杠(\)才能实现乘法运算;
- if...then...fi 是条件语句,后续将会讲解。
运算符 | 说明 | 举例 |
---|---|---|
+ | 加法 | `expr a+a+b` 结果为 30。 |
- | 减法 | `expr a−a−b` 结果为 10。 |
* | 乘法 | `expr a\*a\*b` 结果为 200。 |
/ | 除法 | `expr b/b/a` 结果为 2。 |
% | 取余 | `expr bba` 结果为 0。 |
= | 赋值 | a=$b 将把变量 b 的值赋给 a。 |
== | 相等。用于比较两个数字,相同则返回 true。 | [ a==a==b ] 返回 false。 |
!= | 不相等。用于比较两个数字,不相同则返回 true。 | [ a!=a!=b ] 返回 true。 |
9.2 关系运算符
关系运算符只支持数字,不支持字符串,除非字符串的值是数字。 先来看一个关系运算符的例子:#!/bin/sha=10b=20if [ $a -eq $b ]thenecho "$a -eq $b : a is equal to b"elseecho "$a -eq $b: a is not equal to b"fiif [ $a -ne $b ]thenecho "$a -ne $b: a is not equal to b"elseecho "$a -ne $b : a is equal to b"fiif [ $a -gt $b ]thenecho "$a -gt $b: a is greater than b"elseecho "$a -gt $b: a is not greater than b"fiif [ $a -lt $b ]thenecho "$a -lt $b: a is less than b"elseecho "$a -lt $b: a is not less than b"fiif [ $a -ge $b ]thenecho "$a -ge $b: a is greater or equal to b"elseecho "$a -ge $b: a is not greater or equal to b"fiif [ $a -le $b ]thenecho "$a -le $b: a is less or equal to b"elseecho "$a -le $b: a is not less or equal to b"fi
10 -eq 20: a is not equal to b10 -ne 20: a is not equal to b10 -gt 20: a is not greater than b10 -lt 20: a is less than b10 -ge 20: a is not greater or equal to b10 -le 20: a is less or equal to b
运算符 | 说明 | 举例 |
---|---|---|
-eq | 检测两个数是否相等,相等返回 true。 | [ a−eqa−eqb ] 返回 true。 |
-ne | 检测两个数是否相等,不相等返回 true。 | [ a−nea−neb ] 返回 true。 |
-gt | 检测左边的数是否大于右边的,如果是,则返回 true。 | [ a−gta−gtb ] 返回 false。 |
-lt | 检测左边的数是否小于右边的,如果是,则返回 true。 | [ a−lta−ltb ] 返回 true。 |
-ge | 检测左边的数是否大等于右边的,如果是,则返回 true。 | [ a−gea−geb ] 返回 false。 |
-le | 检测左边的数是否小于等于右边的,如果是,则返回 true。 | [ a−lea−leb ] 返回 true。 |
9.3 布尔运算符
先来看一个布尔运算符的例子:#!/bin/sha=10b=20if [ $a != $b ]thenecho "$a != $b : a is not equal to b"elseecho "$a != $b: a is equal to b"fiif [ $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"fiif [ $a -lt 100 -o $b -gt 100 ]thenecho "$a -lt 100 -o $b -gt 100 : returns true"elseecho "$a -lt 100 -o $b -gt 100 : returns false"fiif [ $a -lt 5 -o $b -gt 100 ]thenecho "$a -lt 100 -o $b -gt 100 : returns true"elseecho "$a -lt 100 -o $b -gt 100 : returns false"fi
10 != 20 : a is not equal to b10 -lt 100 -a 20 -gt 15 : returns true10 -lt 100 -o 20 -gt 100 : returns true10 -lt 5 -o 20 -gt 100 : returns false
运算符 | 说明 | 举例 |
---|---|---|
! | 非运算,表达式为 true 则返回 false,否则返回 true。 | [ ! false ] 返回 true。 |
-o | 或运算,有一个表达式为 true 则返回 true。 | [ a−lt20−oa−lt20−ob -gt 100 ] 返回 true。 |
-a | 与运算,两个表达式都为 true 才返回 true。 | [ a−lt20−aa−lt20−ab -gt 100 ] 返回 false。 |
9.4 字符串运算符
先来看一个例子:#!/bin/sha="abc"b="efg"if [ $a = $b ]thenecho "$a = $b : a is equal to b"elseecho "$a = $b: a is not equal to b"fiif [ $a != $b ]thenecho "$a != $b : a is not equal to b"elseecho "$a != $b: a is equal to b"fiif [ -z $a ]thenecho "-z $a : string length is zero"elseecho "-z $a : string length is not zero"fiif [ -n $a ]thenecho "-n $a : string length is not zero"elseecho "-n $a : string length is zero"fiif [ $a ]thenecho "$a : string is not empty"elseecho "$a : string is empty"fi
abc = efg: a is not equal to babc != efg : a is not equal to b-z abc : string length is not zero-n abc : string length is not zeroabc : string is not empty
运算符 | 说明 | 举例 |
---|---|---|
= | 检测两个字符串是否相等,相等返回 true。 | [ a=a=b ] 返回 false。 |
!= | 检测两个字符串是否相等,不相等返回 true。 | [ a!=a!=b ] 返回 true。 |
-z | 检测字符串长度是否为0,为0返回 true。 | [ -z $a ] 返回 false。 |
-n | 检测字符串长度是否为0,不为0返回 true。 | [ -z $a ] 返回 true。 |
str | 检测字符串是否为空,不为空返回 true。 | [ $a ] 返回 true。 |
9.5 文件测试运算符
文件测试运算符用于检测 Unix 文件的各种属性。 例如,变量 file 表示文件“/var/www/tutorialspoint/unix/test.sh”,它的大小为100字节,具有 rwx 权限。下面的代码,将检测该文件的各种属性:#!/bin/shfile="/var/www/tutorialspoint/unix/test.sh"if [ -r $file ]thenecho "File has read access"elseecho "File does not have read access"fiif [ -w $file ]thenecho "File has write permission"elseecho "File does not have write permission"fiif [ -x $file ]thenecho "File has execute permission"elseecho "File does not have execute permission"fiif [ -f $file ]thenecho "File is an ordinary file"elseecho "This is sepcial file"fiif [ -d $file ]thenecho "File is a directory"elseecho "This is not a directory"fiif [ -s $file ]thenecho "File size is zero"elseecho "File size is not zero"fiif [ -e $file ]thenecho "File exists"elseecho "File does not exist"fi
File has read accessFile has write permissionFile has execute permissionFile is an ordinary fileThis is not a directoryFile size is zeroFile exists
操作符 | 说明 | 举例 |
---|---|---|
-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。 |
10. Shell注释
#--------------------------------------------# 这是一个自动打ipa的脚本,基于webfrogs的ipa-build书写:# https://github.com/webfrogs/xcode_shell/blob/master/ipa-build# 功能:自动为etao ios app打包,产出物为14个渠道的ipa包# 特色:全自动打包,不需要输入任何参数#--------------------------------------------##### 用户配置区 开始 ######## 项目根目录,推荐将此脚本放在项目的根目录,这里就不用改了# 应用名,确保和Xcode里Product下的target_name.app名字一致###### 用户配置区 结束 #####
11. Shell字符串
11.1 单引号
str='this is a string'
- 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;
- 单引号字串中不能出现单引号(对单引号使用转义符后也不行)。
11.2 双引号
your_name='qinjx'str="Hello, I know your are \"$your_name\"! \n"
- 双引号里可以有变量
- 双引号里可以出现转义字符
11.3 拼接字符串
your_name="qinjx"greeting="hello, "$your_name" !"greeting_1="hello, ${your_name} !"echo $greeting $greeting_1
11.4 获取字符串长度
string="abcd"echo ${#string} #输出 4
11.5 提取子字符串
string="alibaba is a great company"echo ${string:1:4} #输出liba
11.6 查找子字符串
string="alibaba is a great company"echo `expr index "$string" is`
12. Shell数组
12.1 定义数组
在Shell中,用括号来表示数组,数组元素用“空格”符号分割开。定义数组的一般形式为: array_name=(value1 ... valuen) 例如:array_name=(value0 value1 value2 value3)
array_name=(value0value1value2value3)
array_name[0]=value0array_name[1]=value1array_name[2]=value2
12.2 读取数组
读取数组元素值的一般格式是: ${array_name[index]} 例如:valuen=${array_name[2]}
#!/bin/shNAME[0]="Zara"NAME[1]="Qadir"NAME[2]="Mahnaz"NAME[3]="Ayan"NAME[4]="Daisy"echo "First Index: ${NAME[0]}"echo "Second Index: ${NAME[1]}"
$./test.shFirst Index: ZaraSecond Index: Qadir
${array_name[*]}${array_name[@]}
#!/bin/shNAME[0]="Zara"NAME[1]="Qadir"NAME[2]="Mahnaz"NAME[3]="Ayan"NAME[4]="Daisy"echo "First Method: ${NAME[*]}"echo "Second Method: ${NAME[@]}"
$./test.shFirst Method: Zara Qadir Mahnaz Ayan DaisySecond Method: Zara Qadir Mahnaz Ayan Daisy
12.3 获取数组的长度
获取数组长度的方法与获取字符串长度的方法相同,例如:# 取得数组元素的个数length=${#array_name[@]}# 或者length=${#array_name[*]}# 取得数组单个元素的长度lengthn=${#array_name[n]}
13. echo命令
echo arg
13.1 显示转义字符
echo "\"It is a test\""
"It is a test"
13.2 显示变量
name="OK"echo "$name It is a test"
OK It is a test
mouth=8echo "${mouth}-1-2009"
8-1-2009
13.3 显示换行
echo "OK!\n"echo "It is a test"
OK!It is a test
13.4 显示不换行
echo "OK!\c"echo "It is a test"
OK!It si a test
13.5 显示结果重定向至文件
echo "It is a test" > myfile
13.6 原样输出字符串
若需要原样输出字符串(不进行转义),请使用单引号。例如:echo '$name\"'
13.7 显示命令执行结果
echo `date`
14. printf命令
$printf "Hello, Shell\n"Hello, Shell$
printf format-string [arguments...]
- printf 命令不用加括号
- format-string 可以没有引号,但最好加上,单引号双引号均可。
- 参数多于格式控制符(%)时,format-string 可以重用,可以将所有参数都转换。
- arguments 使用空格分隔,不用逗号。
# format-string为双引号$ printf "%d %s\n" 1 "abc"1 abc# 单引号与双引号效果一样$ printf '%d %s\n' 1 "abc"1 abc# 没有引号也可以输出$ printf %s abcdefabcdef# 格式只指定了一个参数,但多出的参数仍然会按照该格式输出,format-string 被重用$ printf %s abc defabcdef$ printf "%s\n" abc defabcdef$ printf "%s %s %s\n" a b c d e f g h i ja b cd e fg h ij# 如果没有 arguments,那么 %s 用NULL代替,%d 用 0 代替$ printf "%s and %d \n"and 0# 如果以 %d 的格式来显示字符串,那么会有警告,提示无效的数字,此时默认置为 0$ printf "The first program always prints'%s,%d\n'" Hello Shell-bash: printf: Shell: invalid numberThe first program always prints 'Hello,0'$
15. if...else语句
- if ... fi 语句;
- if ... else ... fi 语句;
- if ... elif ... else ... fi 语句。
1) if ... else 语句
if ... else 语句的语法:if [ expression ]then Statement(s) to be executed if expression is truefi如果 expression 返回 true,then 后边的语句将会被执行;如果返回 false,不会执行任何语句。 最后必须以 fi 来结尾闭合 if,fi 就是 if 倒过来拼写,后面也会遇见。 注意:expression 和方括号([ ])之间必须有空格,否则会有语法错误。 举个例子:
#!/bin/sha=10b=20if [ $a == $b ]thenecho "a is equal to b"fiif [ $a != $b ]thenecho "a is not equal to b"fi
a is not equal to b
2) if ... else ... fi 语句
if ... else ... fi 语句的语法:if [ expression ]then Statement(s) to be executed if expression is trueelse Statement(s) to be executed if expression is not truefi如果 expression 返回 true,那么 then 后边的语句将会被执行;否则,执行 else 后边的语句。 举个例子:
#!/bin/sha=10b=20if [ $a == $b ]thenecho "a is equal to b"elseecho "a is not equal to b"fi
a is not equal to b
3) if ... elif ... fi 语句
if ... elif ... fi 语句可以对多个条件进行判断,语法为:if [ expression 1 ]then Statement(s) to be executed if expression 1 is trueelif [ expression 2 ]then Statement(s) to be executed if expression 2 is trueelif [ expression 3 ]then Statement(s) to be executed if expression 3 is trueelse Statement(s) to be executed if no expression is truefi哪一个 expression 的值为 true,就执行哪个 expression 后面的语句;如果都为 false,那么不执行任何语句。 举个例子:
#!/bin/sha=10b=20if [ $a == $b ]thenecho "a is equal to b"elif [ $a -gt $b ]thenecho "a is greater than b"elif [ $a -lt $b ]thenecho "a is less than b"elseecho "None of the condition met"fi
a is less than bif ... else 语句也可以写成一行,以命令的方式来运行,像这样:
if test $[2*3] -eq $[1+5]; then echo 'The two numbers are equal!'; fi;
num1=$[2*3]num2=$[1+5]if test $[num1] -eq $[num2]thenecho 'The two numbers are equal!'elseecho 'The two numbers are not equal!'fi
The two numbers are equal!
16. case esac命令
模式1) command1 command2 command3 ;;模式2) command1 command2 command3 ;;*) command1 command2 command3 ;;esaccase工作方式如上所示。取值后面必须为关键字 in,每一模式必须以右括号结束。取值可以为变量或常数。匹配发现取值符合某一模式后,其间所有命令开始执行直至 ;;。;; 与其他语言中的 break 类似,意思是跳到整个 case 语句的最后。 取值将检测匹配的每一个模式。一旦模式匹配,则执行完匹配模式相应命令后不再继续其他模式。如果无一匹配模式,使用星号 * 捕获该值,再执行后面的命令。 下面的脚本提示输入1到4,与每一种模式进行匹配:
echo 'Input a number between 1 to 4'echo 'Your number is:\c'read aNumcase $aNum in1) echo 'You select 1';;2) echo 'You select 2';;3) echo 'You select 3';;4) echo 'You select 4';;*) echo 'You do not select a number between 1 to 4';;esac
Input a number between 1 to 4Your number is:3You select 3
#!/bin/bashoption="${1}"case ${option} in-f) FILE="${2}"echo "File name is $FILE";;-d) DIR="${2}"echo "Dir name is $DIR";;*)echo "`basename ${0}`:usage: [-f file] | [-d directory]"exit 1 # Command to come out of the program with status 1;;esac
$./test.shtest.sh: usage: [ -f filename ] | [ -d directory ]$ ./test.sh -f index.htm$ vi test.sh$ ./test.sh -f index.htmFile name is index.htm$ ./test.sh -d unixDir name is unix$
17. for循环
for 变量 in 列表do command1 command2 ... commandNdone列表是一组值(数字、字符串等)组成的序列,每个值通过空格分隔。每循环一次,就将列表中的下一个值赋给变量。 in 列表是可选的,如果不用它,for 循环使用命令行的位置参数。 例如,顺序输出当前列表中的数字:
for loop in 1 2 3 4 5doecho "The value is: $loop"done
The value is: 1The value is: 2The value is: 3The value is: 4The value is: 5
for str in 'This is a string'doecho $strdone
This is a string
#!/bin/bashfor FILE in $HOME/.bash*doecho $FILEdone
/root/.bash_history/root/.bash_logout/root/.bash_profile/root/.bashrc
18. while循环
while commanddo Statement(s) to be executed if command is truedone命令执行完毕,控制返回循环顶部,从头开始直至测试条件为假。 以下是一个基本的while循环,测试条件是:如果COUNTER小于5,那么返回 true。COUNTER从0开始,每次循环处理时,COUNTER加1。运行上述脚本,返回数字1到5,然后终止。
COUNTER=0while [ $COUNTER -lt 5 ]doCOUNTER='expr $COUNTER+1'echo $COUNTERdone
12345
echo 'typeto terminate'echo -n 'enter your most liked film: 'while read FILMdoecho "Yeah! great film the $FILM"done
typeto terminateenter your most liked film: Sound of MusicYeah! great film the Sound of Music
19. until命令
until commanddo Statement(s) to be executed until command is truedonecommand 一般为条件表达式,如果返回值为 false,则继续执行循环体内的语句,否则跳出循环。 例如,使用 until 命令输出 0 ~ 9 的数字:
#!/bin/basha=0until [ ! $a -lt 10 ]doecho $aa=`expr $a + 1`done
0123456789
20. 跳出循环
20.1 break命令
break命令允许跳出所有循环(终止执行后面的所有循环)。 下面的例子中,脚本进入死循环直至用户输入数字大于5。要跳出这个循环,返回到shell提示符下,就要使用break命令。#!/bin/bashwhile :doecho -n "Input a number between 1 to 5: "read aNumcase $aNum in1|2|3|4|5) echo "Your number is $aNum!";;*) echo "You do not select a number between 1 to 5, game is over!"break;;esacdone
break n
#!/bin/bashfor var1 in 1 2 3dofor var2 in 0 5doif [ $var1 -eq 2 -a $var2 -eq 0 ]thenbreak 2elseecho "$var1 $var2"fidonedone
1 01 5
20.2 continue命令
continue命令与break命令类似,只有一点差别,它不会跳出所有循环,仅仅跳出当前循环。 对上面的例子进行修改:#!/bin/bashwhile :doecho -n "Input a number between 1 to 5: "read aNumcase $aNum in1|2|3|4|5) echo "Your number is $aNum!";;*) echo "You do not select a number between 1 to 5!"continueecho "Game is over!";;esacdone
echo "Game is over!"
#!/bin/bashNUMS="1 2 3 4 5 6 7"for NUM in $NUMSdoQ=`expr $NUM % 2`if [ $Q -eq 0 ]thenecho "Number is an even number!!"continuefiecho "Found odd number"done
Found odd numberNumber is an even number!!Found odd numberNumber is an even number!!Found odd numberNumber is an even number!!Found odd number
21. Shell函数
function_name () { list of commands [ return value ]}如果你愿意,也可以在函数名前加上关键字 function:
function function_name () { list of commands [ return value ]}函数返回值,可以显式增加return语句;如果不加,会将最后一条命令运行结果作为返回值。 Shell 函数返回值只能是整数,一般用来表示函数执行成功与否,0表示成功,其他值表示失败。如果 return 其他数据,比如一个字符串,往往会得到错误提示:“numeric argument required”。 如果一定要让函数返回字符串,那么可以先定义一个变量,用来接收函数的计算结果,脚本在需要的时候访问这个变量来获得函数返回值。= 先来看一个例子:
#!/bin/bash# Define your function hereHello () {echo "Url is http://see.xidian.edu.cn/cpp/shell/"}# Invoke your functionHello
$./test.shHello World$
#!/bin/bashfunWithReturn(){echo "The function is to get the sum of two numbers..."echo -n "Input first number: "read aNumecho -n "Input another number: "read anotherNumecho "The two numbers are $aNum and $anotherNum !"return $(($aNum+$anotherNum))}funWithReturn# Capture value returnd by last commandret=$?echo "The sum of two numbers is $ret !"
The function is to get the sum of two numbers...Input first number: 25Input another number: 50The two numbers are 25 and 50 !The sum of two numbers is 75 !
#!/bin/bash# Calling one function from anothernumber_one () {echo "Url_1 is http://see.xidian.edu.cn/cpp/shell/"number_two}number_two () {echo "Url_2 is http://see.xidian.edu.cn/cpp/u/xitong/"}number_one
Url_1 is http://see.xidian.edu.cn/cpp/shell/Url_2 is http://see.xidian.edu.cn/cpp/u/xitong/
$unset .f function_name
22. Shell函数参数
#!/bin/bashfunWithParam(){echo "The value of the first parameter is $1 !"echo "The value of the second parameter is $2 !"echo "The value of the tenth parameter is $10 !"echo "The value of the tenth parameter is ${10} !"echo "The value of the eleventh parameter is ${11} !"echo "The amount of the parameters is $# !" # 参数个数echo "The string of the parameters is $* !" # 传递给函数的所有参数}funWithParam 1 2 3 4 5 6 7 8 9 34 73
The value of the first parameter is 1 !The value of the second parameter is 2 !The value of the tenth parameter is 10 !The value of the tenth parameter is 34 !The value of the eleventh parameter is 73 !The amount of the parameters is 12 !The string of the parameters is 1 2 3 4 5 6 7 8 9 34 73 !"
特殊变量 | 说明 |
---|---|
$# | 传递给函数的参数个数。 |
$* | 显示所有传递给函数的参数。 |
$@ | 与$*相同,但是略有区别,请查看。 |
$? | 函数的返回值。 |
23. 输入输出重定向
23.1 输出重定向
命令的输出不仅可以是显示器,还可以很容易的转移向到文件,这被称为输出重定向。 命令输出重定向的语法为:$ command > file
$ who > users
$ cat usersoko tty01 Sep 12 07:30ai tty15 Sep 12 13:32ruth tty21 Sep 12 10:10pat tty24 Sep 12 13:07steve tty25 Sep 12 13:03$
$ echo line 1 > users$ cat usersline 1$
$ echo line 2 >> users$ cat usersline 1line 2$
23.2 输入重定向
和输出重定向一样,Unix 命令也可以从文件获取输入,语法为:command < file
$ wc -l users2 users$
$ wc -l < users2$
23.3 重定向深入讲解
一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件:- 标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。
- 标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。
- 标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。
$command 2 > file
$command 2 >> file
$command > file 2>&1
$command >> file 2>&1
$command < file1 >file2
命令 | 说明 |
---|---|
command > file | 将输出重定向到 file。 |
command < file | 将输入重定向到 file。 |
command >> file | 将输出以追加的方式重定向到 file。 |
n > file | 将文件描述符为 n 的文件重定向到 file。 |
n >> file | 将文件描述符为 n 的文件以追加的方式重定向到 file。 |
n >& m | 将输出文件 m 和 n 合并。 |
n <& m | 将输入文件 m 和 n 合并。 |
<< tag | 将开始标记 tag 和结束标记 tag 之间的内容作为输入。 |
Here Document
Here Document 目前没有统一的翻译,这里暂译为”嵌入文档“。Here Document 是 Shell 中的一种特殊的重定向方式,它的基本的形式如下:- command << delimiter
- document
- delimiter
- 结尾的delimiter 一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和 tab 缩进。
- 开始的delimiter前后的空格会被忽略掉。
$wc -l << EOF This is a simple lookup program for good (and bad) restaurants in Cape Town.EOF3$
#!/bin/bashcat << EOFThis is a simple lookup programfor good (and bad) restaurantsin Cape Town.EOF
This is a simple lookup programfor good (and bad) restaurantsin Cape Town.
#!/bin/shfilename=test.txtvi $filename <
$ sh test.shVim: Warning: Input is not from a terminal$
$ cat test.txtThis file was created automatically froma shell script$
/dev/null 文件
如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null:$ command > /dev/null
$ command > /dev/null 2>&1
24. 文件包含
. filename
source filename
url="http://see.xidian.edu.cn/cpp/view/2738.html"
#!/bin/bash. ./subscript.shecho $url
$chomd +x main.sh./main.shhttp://see.xidian.edu.cn/cpp/view/2738.html$