shell脚本入门

1. Shell简介

  Shell自己是一个用C语言编写的程序,它是用户使用Unix/Linux的桥梁,用户的大部分工做都是经过Shell完成的。Shell既是一种命令语言,又是一种程序设计语言。做为命令语言,它交互式地解释和执行用户输入的命令;做为程序设计语言,它定义了各类变量和参数,并提供了许多在高级语言中才具备的控制结构,包括循环和分支。html

  它虽然不是Unix/Linux系统内核的一部分,但它调用了系统核心的大部分功能来执行程序、创建文件并以并行的方式协调各个程序的运行。所以,对于用户来讲,shell是最重要的实用程序,深刻了解和熟练掌握shell的特性极其使用方法,是用好Unix/Linux系统的关键。linux

  能够说,shell使用的熟练程度反映了用户对Unix/Linux使用的熟练程度。ios

  注意:单独地学习 Shell 是没有意义的,请先参考Unix/Linux入门教程,了解 Unix/Linux 基础。git

  Shell有两种执行命令的方式:github

  交互式(Interactive):解释执行用户的命令,用户输入一条命令,Shell就解释执行一条。web

  批处理(Batch):用户事先写一个Shell脚本(Script),其中有不少条命令,让Shell一次把这些命令执行完,而没必要一条一条地敲命令。shell

  Shell脚本和编程语言很类似,也有变量和流程控制语句,但Shell脚本是解释执行的,不须要编译,Shell程序从脚本中一行一行读取并执行这些命令,至关于一个用户把脚本中的命令一行一行敲到Shell提示符下执行。express

  Shell初学者请注意,在日常应用中,建议不要用 root 账号运行 Shell 。做为普通用户,无论您有意仍是无心,都没法破坏系统;但若是是 root,那就不一样了,只要敲几个字母,就可能致使灾难性后果。编程

2. 几种常见的Shell

  上面提到过,Shell是一种脚本语言,那么,就必须有解释器来执行这些脚本。

  Unix/Linux上常见的Shell脚本解释器有bash、sh、csh、ksh等,习惯上把它们称做一种Shell。咱们常说有多少种Shell,其实说的是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),这个过程被称做“编译”。
  运行程序时,直接读取目标代码(object code)。因为编译后的目标代码(object code)很是接近计算机底层,所以执行效率很高,这是编译型语言的优势。
  可是,因为编译型语言多半运做于底层,所处理的是字节、整数、浮点数或是其余机器层级的对象,每每实现一个简单的功能须要大量复杂的代码。例如,在C++里,就很难进行“将一个目录里全部的文件复制到另外一个目录中”之类的简单操做。

  解释型语言

  解释型语言也被称做“脚本语言”。执行这类程序时,解释器(interpreter)须要读取咱们编写的源代码(source code),并将其转换成目标代码(object code),再由计算机运行。由于每次执行程序都多了编译的过程,所以效率有所降低。

  使用脚本编程语言的好处是,它们多半运行在比编译型语言还高的层级,可以轻易处理文件与目录之类的对象;缺点是它们的效率一般不如编译型语言。不过权衡之下,一般使用脚本编程仍是值得的:花一个小时写成的简单脚本,一样的功能用C或C++来编写实现,可能须要两天,并且通常来讲,脚本执行的速度已经够快了,快到足以让人忽略它性能上的问题。脚本编程语言的例子有awk、Perl、Python、Ruby与Shell。

4. 何时使用Shell?

  由于Shell彷佛是各UNIX系统之间通用的功能,而且通过了POSIX的标准化。所以,Shell脚本只要“用心写”一次,便可应用到不少系统上。所以,之因此要使用Shell脚本是基于:
  • 简单性:Shell是一个高级语言;经过它,你能够简洁地表达复杂的操做。
  • 可移植性:使用POSIX所定义的功能,能够作到脚本无须修改就可在不一样的系统上执行。
  • 开发容易:能够在短期内完成一个功能强大又妤用的脚本。
  可是,考虑到Shell脚本的命令限制和效率问题,下列状况通常不使用Shell:
  1. 资源密集型的任务,尤为在须要考虑效率时(好比,排序,hash等等)。
  2. 须要处理大任务的数学操做,尤为是浮点运算,精确运算,或者复杂的算术运算(这种状况通常使用C++或FORTRAN 来处理)。
  3. 有跨平台(操做系统)移植需求(通常使用C 或Java)。
  4. 复杂的应用,在必须使用结构化编程的时候(须要变量的类型检查,函数原型,等等)。
  5. 对于影响系统全局性的关键任务应用。
  6. 对于安全有很高要求的任务,好比你须要一个健壮的系统来防止入侵、破解、恶意破坏等等。
  7. 项目由连串的依赖的各个部分组成。
  8. 须要大规模的文件操做。
  9. 须要多维数组的支持。
  10. 须要数据结构的支持,好比链表或数等数据结构。
  11. 须要产生或操做图形化界面 GUI。
  12. 须要直接操做系统硬件。
  13. 须要 I/O 或socket 接口。
  14. 须要使用库或者遗留下来的老代码的接口。
  15. 私人的、闭源的应用(shell 脚本把代码就放在文本文件中,全世界都能看到)。

  若是你的应用符合上边的任意一条,那么就考虑一下更强大的语言吧——或许是Perl、Tcl、Python、Ruby——或者是更高层次的编译语言好比C/C++,或者是Java。即便如此,你会发现,使用shell来原型开发你的应用,在开发步骤中也是很是有用的。

5. 第一个Shell脚本

  打开文本编辑器,新建一个文件,扩展名为sh(sh表明shell),扩展名并不影响脚本执行,见名知意就好,若是你用php写shell 脚本,扩展名就用php好了。

  输入一些代码:
#!/bin/bash
echo "Hello World !"
  “#!” 是一个约定的标记,它告诉系统这个脚本须要什么解释器来执行,即便用哪种Shell。echo命令用于向窗口输出文本。
  运行Shell脚本有两种方法。

  5.1 做为可执行程序

  将上面的代码保存为test.sh,并 cd 到相应目录:

chmod +x ./test.sh #使脚本具备执行权限
./test.sh #执行脚本
  注意,必定要写成./test.sh,而不是test.sh。运行其它二进制的程序也同样,直接写test.sh,linux系统会去PATH里寻找有没有叫test.sh的,而只有/bin, /sbin, /usr/bin,/usr/sbin等在PATH里,你的当前目录一般不在PATH里,因此写成test.sh是会找不到命令的,要用./test.sh告诉系统说,就在当前目录找。
  经过这种方式运行bash脚本,第一行必定要写对,好让系统查找到正确的解释器。
  这里的"系统",其实就是shell这个应用程序(想象一下Windows Explorer),但我故意写成系统,是方便理解,既然这个系统就是指shell,那么一个使用/bin/sh做为解释器的脚本是否是能够省去第一行呢?是的。

  5.2 做为解释器参数

  这种运行方式是,直接运行解释器,其参数就是shell脚本的文件名,如:
/bin/sh test.sh
/bin/php test.php
  这种方式运行的脚本,不须要在第一行指定解释器信息,写了也没用。
  再看一个例子。下面的脚本使用 read 命令从 stdin 获取输入并赋值给 PERSON 变量,最后在 stdout 上输出:
复制代码
#!/bin/bash
# Author : mozhiyan
# Copyright (c) http://see.xidian.edu.cn/cpp/linux/
# Script follows here:
echo "What is your name?"
read PERSON
echo "Hello, $PERSON"
复制代码
  运行脚本:
chmod +x ./test.sh
$./test.sh
What is your name?
mozhiyan
Hello, mozhiyan

6. Shell变量

  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_name
echo ${your_name}
  变量名外面的花括号是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界,好比下面这种状况:
for skill in Ada Coffe Action Java
do
echo "I am good at ${skill}Script"
done
  若是不给skill变量加花括号,写成echo "I am good at  skillScript"skillScript",解释器就会把skillScript当成一个变量(其值为空),代码执行结果就不是咱们指望的样子了。
推荐给全部变量加上花括号,这是个好的编程习惯。

  6.3 从新定义变量

  已定义的变量,能够被从新定义,如:
myUrl="http://see.xidian.edu.cn/cpp/linux/"
echo ${myUrl}
myUrl="http://see.xidian.edu.cn/cpp/shell/"
echo ${myUrl}
  这样写是合法的,但注意,第二次赋值的时候不能写 myUrl="http://see.xidian.edu.cn/cpp/shell/"使myUrl="http://see.xidian.edu.cn/cpp/shell/",使用变量的时候才加美圆符()。

  6.4 只读变量

  使用 readonly 命令能够将变量定义为只读变量,只读变量的值不能被改变。
  下面的例子尝试更改只读变量,结果报错:
#!/bin/bash
myUrl="http://see.xidian.edu.cn/cpp/shell/"
readonly myUrl
myUrl="http://see.xidian.edu.cn/cpp/danpianji/"
  运行脚本,结果以下:
/bin/sh: NAME: This variable is read only.

  6.5 删除变量

  使用 unset 命令能够删除变量。语法:
unset variable_name
  变量被删除后不能再次使用;unset 命令不能删除只读变量。
  举个例子:
#!/bin/sh
myUrl="http://see.xidian.edu.cn/cpp/u/xitong/"
unset myUrl
echo $myUrl
  上面的脚本没有任何输出。

  6.6 变量类型

  运行shell时,会同时存在三种变量:

  1) 局部变量

  局部变量在脚本或命令中定义,仅在当前shell实例中有效,其余shell启动的程序不能访问局部变量。

  2) 环境变量

  全部的程序,包括shell启动的程序,都能访问环境变量,有些程序须要环境变量来保证其正常运行。必要的时候shell脚本也能够定义环境变量。

  3) shell变量

  shell变量是由shell程序设置的特殊变量。shell变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了shell的正常运行

7.Shell特殊变量

  前面已经讲到,变量名只能包含数字、字母和下划线,由于某些包含其余字符的变量有特殊含义,这样的变量被称为特殊变量。
  例如,$ 表示当前Shell进程的ID,即pid,看下面的代码:
$echo $$
  运行结果: 29949

特殊变量列表
变量 含义
$0 当前脚本的文件名
$n 传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是11,第二个参数是2。
$# 传递给脚本或函数的参数个数。
$* 传递给脚本或函数的全部参数。
$@ 传递给脚本或函数的全部参数。被双引号(" ")包含时,与 $* 稍有不一样,下面将会讲到。
$? 上个命令的退出状态,或函数的返回值。
$$ 当前Shell进程ID。对于 Shell 脚本,就是这些脚本所在的进程ID。

  命令行参数

  运行脚本时传递给脚本的参数称为命令行参数。命令行参数用  nn表示,例如,1 表示第一个参数,$2 表示第二个参数,依次类推。

  请看下面的脚本:
复制代码
#!/bin/bash
echo "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 Ali
File Name : ./test.sh
First Parameter : Zara
Second Parameter : Ali
Quoted Values: Zara Ali
Quoted Values: Zara Ali
Total Number of Parameters : 2
复制代码

  ∗和@ 的区别

  ∗和@ 都表示传递给函数或脚本的全部参数,不被双引号(" ")包含时,都以"1""1""2" … "$n" 的形式输出全部参数。
  可是当它们被双引号(" ")包含时,"""∗"会将全部的参数做为一个总体,以"1 22…n"的形式输出全部参数;"@""@"会将各个参数分开,以"1" "2""2"…"n" 的形式输出全部参数。
  下面的例子能够清楚的看到 ∗和@ 的区别:
复制代码
#!/bin/bash
echo "\$*=" $*
echo "\"\$*\"=" "$*"
echo "\$@=" $@
echo "\"\$@\"=" "$@"
echo "print each param from \$*"
for var in $*
do
echo "$var"
done
echo "print each param from \$@"
for var in $@
do
echo "$var"
done
echo "print each param from \"\$*\""
for var in "$*"
do
echo "$var"
done
echo "print each param from \"\$@\""
for var in "$@"
do
echo "$var"
复制代码
  1. done
  执行 ./test.sh "a" "b" "c" "d",看到下面的结果:
复制代码
$*=  a b c d
"$*"= a b c d
$@=  a b c d
"$@"= a b c d
print each param from $*
a
b
c
d
print each param from $@
a
b
c
d
print each param from "$*"
a b c d
print each param from "$@"
a
b
c
d
复制代码

  退出状态

  $? 能够获取上一个命令的退出状态。所谓退出状态,就是上一个命令执行后的返回结果。

  退出状态是一个数字,通常状况下,大部分命令执行成功会返回 0,失败返回 1。

  不过,也有一些命令返回其余值,表示不一样类型的错误。

  下面例子中,命令成功执行:
 
  
复制代码
$./test.sh Zara Ali
File Name : ./test.sh
First Parameter : Zara
Second Parameter : Ali
Quoted Values: Zara Ali
Quoted Values: Zara Ali
Total Number of Parameters : 2
$echo $?
0
$
复制代码
  $? 也能够表示函数的返回值,后续将会讲解。

8. Shell替换

  若是表达式中包含特殊字符,Shell 将会进行替换。例如,在双引号中使用变量就是一种替换,转义字符也是一种替换。
  举个例子:
#!/bin/bash
a=10
echo -e "Value of a is $a \n"
  运行结果:
Value of a is 10
  这里 -e 表示对转义字符进行替换。若是不使用 -e 选项,将会原样输出:
Value of a is 10\n
  下面的转义字符均可以用在 echo 中:
转义字符 含义
\\ 反斜杠
\a 警报,响铃
\b 退格(删除键)
\f 换页(FF),将当前位置移到下页开头
\n 换行
\r 回车
\t 水平制表符(tab键) 
\v 垂直制表符
  可使用 echo 命令的 -E 选项禁止转义,默认也是不转义的;使用 -n 选项能够禁止插入换行符。

  命令替换

  命令替换是指Shell能够先执行命令,将输出结果暂时保存,在适当的地方输出。
  命令替换的语法:
`command`
  注意是反引号,不是单引号,这个键位于 Esc 键下方。
  下面的例子中,将命令执行结果保存在变量中:
复制代码
#!/bin/bash
DATE=`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 2009
Logged in user are 1
Uptime is Thu Jul  2 03:59:57 MST 2009
03: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/bash

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
echo ${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
复制代码

9. Shell运算符

  Bash 支持不少运算符,包括算数运算符、关系运算符、布尔运算符、字符串运算符和文件测试运算符。
  原生bash不支持简单的数学运算,可是能够经过其余命令来实现,例如 awk 和 expr,expr 最经常使用。
  expr 是一款表达式计算工具,使用它能完成表达式的求值操做。
  例如,两个数相加:
#!/bin/bash
val=`expr 2 + 2`
echo "Total value : $val"
  运行脚本输出:
Total value : 4
两点注意:
  • 表达式和运算符之间要有空格,例如 2+2 是不对的,必须写成 2 + 2,这与咱们熟悉的大多数编程语言不同。
  • 完整的表达式要被 ` ` 包含,注意这个字符不是经常使用的单引号,在 Esc 键下边。

  9.1 算术运算符

  先来看一个使用算术运算符的例子:
复制代码
#!/bin/sh
a=10
b=20
val=`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 ]
then
echo "a is equal to b"
fi
if [ $a != $b ]
then
echo "a is not equal to b"
fi
复制代码
  运行结果:
复制代码
a + b : 30
a - b : -10
a * b : 200
b / a : 2
b % a : 0
a is not equal to b
复制代码
  注意:
  • 乘号(*)前边必须加反斜杠(\)才能实现乘法运算;
  • if...then...fi 是条件语句,后续将会讲解。
算术运算符列表
运算符 说明 举例
+ 加法 `expr a+a+b` 结果为 30。
- 减法 `expr aa−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。

  注意:条件表达式要放在方括号之间,而且要有空格,例如 [ a==a==b] 是错误的,必须写成 [ a==a==b ]。

  9.2 关系运算符

  关系运算符只支持数字,不支持字符串,除非字符串的值是数字。
  先来看一个关系运算符的例子:
复制代码
#!/bin/sh
a=10
b=20
if [ $a -eq $b ]
then
echo "$a -eq $b : a is equal to b"
else
echo "$a -eq $b: a is not equal to b"
fi
if [ $a -ne $b ]
then
echo "$a -ne $b: a is not equal to b"
else
echo "$a -ne $b : a is equal to b"
fi
if [ $a -gt $b ]
then
echo "$a -gt $b: a is greater than b"
else
echo "$a -gt $b: a is not greater than b"
fi
if [ $a -lt $b ]
then
echo "$a -lt $b: a is less than b"
else
echo "$a -lt $b: a is not less than b"
fi
if [ $a -ge $b ]
then
echo "$a -ge $b: a is greater or equal to b"
else
echo "$a -ge $b: a is not greater or equal to b"
fi
if [ $a -le $b ]
then
echo "$a -le $b: a is less or equal to b"
else
echo "$a -le $b: a is not less or equal to b"
fi
复制代码
运行结果:
复制代码
10 -eq 20: a is not equal to b
10 -ne 20: a is not equal to b
10 -gt 20: a is not greater than b
10 -lt 20: a is less than b
10 -ge 20: a is not greater or equal to b
10 -le 20: a is less or  equal to b
复制代码
关系运算符列表
运算符 说明 举例
-eq 检测两个数是否相等,相等返回 true。 aeqa−eqb ] 返回 true。
-ne 检测两个数是否相等,不相等返回 true。 anea−neb ] 返回 true。
-gt 检测左边的数是否大于右边的,若是是,则返回 true。 agta−gtb ] 返回 false。
-lt 检测左边的数是否小于右边的,若是是,则返回 true。 alta−ltb ] 返回 true。
-ge 检测左边的数是否大等于右边的,若是是,则返回 true。 agea−geb ] 返回 false。
-le 检测左边的数是否小于等于右边的,若是是,则返回 true。 alea−leb ] 返回 true。

  9.3 布尔运算符

  先来看一个布尔运算符的例子:
复制代码
#!/bin/sh
a=10
b=20
if [ $a != $b ]
then
echo "$a != $b : a is not equal to b"
else
echo "$a != $b: a is equal to b"
fi
if [ $a -lt 100 -a $b -gt 15 ]
then
echo "$a -lt 100 -a $b -gt 15 : returns true"
else
echo "$a -lt 100 -a $b -gt 15 : returns false"
fi
if [ $a -lt 100 -o $b -gt 100 ]
then
echo "$a -lt 100 -o $b -gt 100 : returns true"
else
echo "$a -lt 100 -o $b -gt 100 : returns false"
fi
if [ $a -lt 5 -o $b -gt 100 ]
then
echo "$a -lt 100 -o $b -gt 100 : returns true"
else
echo "$a -lt 100 -o $b -gt 100 : returns false"
fi
复制代码
  运行结果:
10 != 20 : a is not equal to b
10 -lt 100 -a 20 -gt 15 : returns true
10 -lt 100 -o 20 -gt 100 : returns true
10 -lt 5 -o 20 -gt 100 : returns false
布尔运算符列表
运算符 说明 举例
! 非运算,表达式为 true 则返回 false,不然返回 true。 [ ! false ] 返回 true。
-o 或运算,有一个表达式为 true 则返回 true。 alt20oa−lt20−ob -gt 100 ] 返回 true。
-a 与运算,两个表达式都为 true 才返回 true。 alt20aa−lt20−ab -gt 100 ] 返回 false。

  9.4 字符串运算符

  先来看一个例子:
复制代码
#!/bin/sh
a="abc"
b="efg"
if [ $a = $b ]
then
echo "$a = $b : a is equal to b"
else
echo "$a = $b: a is not equal to b"
fi
if [ $a != $b ]
then
echo "$a != $b : a is not equal to b"
else
echo "$a != $b: a is equal to b"
fi
if [ -z $a ]
then
echo "-z $a : string length is zero"
else
echo "-z $a : string length is not zero"
fi
if [ -n $a ]
then
echo "-n $a : string length is not zero"
else
echo "-n $a : string length is zero"
fi
if [ $a ]
then
echo "$a : string is not empty"
else
echo "$a : string is empty"
fi
复制代码
  运行结果:
abc = efg: a is not equal to b
abc != efg : a is not equal to b
-z abc : string length is not zero
-n abc : string length is not zero
abc : 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/sh
file="/var/www/tutorialspoint/unix/test.sh"
if [ -r $file ]
then
echo "File has read access"
else
echo "File does not have read access"
fi
if [ -w $file ]
then
echo "File has write permission"
else
echo "File does not have write permission"
fi
if [ -x $file ]
then
echo "File has execute permission"
else
echo "File does not have execute permission"
fi
if [ -f $file ]
then
echo "File is an ordinary file"
else
echo "This is sepcial file"
fi
if [ -d $file ]
then
echo "File is a directory"
else
echo "This is not a directory"
fi
if [ -s $file ]
then
echo "File size is zero"
else
echo "File size is not zero"
fi
if [ -e $file ]
then
echo "File exists"
else
echo "File does not exist"
fi
复制代码
  运行结果:
复制代码
File has read access
File has write permission
File has execute permission
File is an ordinary file
This is not a directory
File size is zero
File 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注释

  以“#”开头的行就是注释,会被解释器忽略。
  sh里没有多行注释,只能每一行加一个#号。只能像这样:
复制代码
#--------------------------------------------
# 这是一个自动打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字符串

  字符串是shell编程中最经常使用最有用的数据类型(除了数字和字符串,也没啥其它类型好用了),字符串能够用单引号,也能够用双引号,也能够不用引号。单双引号的区别跟PHP相似。

  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数组

  Shell在编程方面比Windows批处理强大不少,不管是在循环、运算。

  bash支持一维数组(不支持多维数组),而且没有限定数组的大小。相似与C语言,数组元素的下标由0开始编号。获取数组中的元素要利用下标,下标能够是整数或算术表达式,其值应大于或等于0。

  12.1 定义数组

  在Shell中,用括号来表示数组,数组元素用“空格”符号分割开。定义数组的通常形式为:
  array_name=(value1 ... valuen)
  例如:
array_name=(value0 value1 value2 value3)
或者
复制代码
array_name=(
value0
value1
value2
value3
)
复制代码
  还能够单独定义数组的各个份量:
array_name[0]=value0
array_name[1]=value1
array_name[2]=value2
  能够不使用连续的下标,并且下标的范围没有限制。

  12.2 读取数组

  读取数组元素值的通常格式是:
  ${array_name[index]}
  例如:
valuen=${array_name[2]}
  举个例子:
复制代码
#!/bin/sh
NAME[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.sh
First Index: Zara
Second Index: Qadir
  使用@ 或 * 能够获取数组中的全部元素,例如:
${array_name[*]}
${array_name[@]}
  举个例子:
复制代码
#!/bin/sh
NAME[0]="Zara"
NAME[1]="Qadir"
NAME[2]="Mahnaz"
NAME[3]="Ayan"
NAME[4]="Daisy"
echo "First Method: ${NAME[*]}"
echo "Second Method: ${NAME[@]}"
复制代码
  运行脚本,输出:
 
  
$./test.sh
First Method: Zara Qadir Mahnaz Ayan Daisy
Second Method: Zara Qadir Mahnaz Ayan Daisy

  12.3 获取数组的长度

  获取数组长度的方法与获取字符串长度的方法相同,例如:
复制代码
# 取得数组元素的个数
length=${#array_name[@]}
# 或者
length=${#array_name[*]}
# 取得数组单个元素的长度
lengthn=${#array_name[n]}
复制代码

13. echo命令

  echo是Shell的一个内部指令,用于在屏幕上打印出指定的字符串。命令格式:
echo arg
  您可使用echo实现更复杂的输出格式控制。

  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=8
echo "${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 命令用于格式化输出, 是echo命令的加强版。它是C语言printf()库函数的一个有限的变形,而且在语法上有些不一样。
  注意:printf 由 POSIX 标准所定义,移植性要比 echo 好。
  如同 echo 命令,printf 命令也能够输出简单的字符串:
$printf "Hello, Shell\n"
Hello, Shell
$
  printf 不像 echo 那样会自动换行,必须显式添加换行符(\n)。
  printf 命令的语法:
printf  format-string  [arguments...]
  format-string 为格式控制字符串,arguments 为参数列表。
  printf()在C语言入门教程中已经讲到,功能和用法与 printf 命令相似,请查看: C语言格式输出函数printf()详解
  这里仅说明与C语言printf()函数的不一样:
  • 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 abcdef
abcdef
# 格式只指定了一个参数,但多出的参数仍然会按照该格式输出,format-string 被重用
$ printf %s abc def
abcdef
$ printf "%s\n" abc def
abc
def
$ printf "%s %s %s\n" a b c d e f g h i j
a b c
d e f
g h i
j
# 若是没有 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 number
The first program always prints 'Hello,0'
$
复制代码
  注意,根据POSIX标准,浮点格式%e、%E、%f、%g与%G是“不须要被支持”。这是由于awk支持浮点预算,且有它本身的printf语句。这样Shell程序中须要将浮点数值进行格式化的打印时,可以使用小型的awk程序实现。然而,内建于bash、ksh93和zsh中的printf命令都支持浮点格式。

15. if...else语句

  if 语句经过关系运算符判断表达式的真假来决定执行哪一个分支。Shell 有三种 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 true
fi
  若是 expression 返回 true,then 后边的语句将会被执行;若是返回 false,不会执行任何语句。
  最后必须以 fi 来结尾闭合 if,fi 就是 if 倒过来拼写,后面也会碰见。
  注意:expression 和方括号([ ])之间必须有空格,不然会有语法错误。
  举个例子:
复制代码
#!/bin/sh
a=10
b=20
if [ $a == $b ]
then
echo "a is equal to b"
fi
if [ $a != $b ]
then
echo "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 true
else
   Statement(s) to be executed if expression is not true
fi
  若是 expression 返回 true,那么 then 后边的语句将会被执行;不然,执行 else 后边的语句。
  举个例子:
复制代码
#!/bin/sh
a=10
b=20
if [ $a == $b ]
then
echo "a is equal to b"
else
echo "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 true
elif [ expression 2 ]
then
   Statement(s) to be executed if expression 2 is true
elif [ expression 3 ]
then
   Statement(s) to be executed if expression 3 is true
else
   Statement(s) to be executed if no expression is true
fi
  哪个 expression 的值为 true,就执行哪一个 expression 后面的语句;若是都为 false,那么不执行任何语句。
  举个例子:
复制代码
#!/bin/sh
a=10
b=20
if [ $a == $b ]
then
echo "a is equal to b"
elif [ $a -gt $b ]
then
echo "a is greater than b"
elif [ $a -lt $b ]
then
echo "a is less than b"
else
echo "None of the condition met"
fi
复制代码
  运行结果:
a is less than b
  if ... else 语句也能够写成一行,以命令的方式来运行,像这样:
if test $[2*3] -eq $[1+5]; then echo 'The two numbers are equal!'; fi;
  if ... else 语句也常常与 test 命令结合使用,以下所示:
复制代码
num1=$[2*3]
num2=$[1+5]
if test $[num1] -eq $[num2]
then
echo 'The two numbers are equal!'
else
echo 'The two numbers are not equal!'
fi
复制代码
  输出:
 
  
The two numbers are equal!
  test 命令用于检查某个条件是否成立,与方括号([ ])相似。

16. case esac命令

  case ... esac 与其余语言中的 switch ... case 语句相似,是一种多分枝选择结构。
  case 语句匹配一个值或一个模式,若是匹配成功,执行相匹配的命令。case语句格式以下:
  case 值 in
模式1)
    command1
    command2
    command3
    ;;
模式2)
    command1
    command2
    command3
    ;;
*)
    command1
    command2
    command3
    ;;
esac
  case工做方式如上所示。取值后面必须为关键字 in,每一模式必须以右括号结束。取值能够为变量或常数。匹配发现取值符合某一模式后,其间全部命令开始执行直至 ;;。;; 与其余语言中的 break 相似,意思是跳到整个 case 语句的最后。
  取值将检测匹配的每个模式。一旦模式匹配,则执行完匹配模式相应命令后再也不继续其余模式。若是无一匹配模式,使用星号 * 捕获该值,再执行后面的命令。
  下面的脚本提示输入1到4,与每一种模式进行匹配:
复制代码
echo 'Input a number between 1 to 4'
echo 'Your number is:\c'
read aNum
case $aNum in
1) 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 4
Your number is:3
You select 3
  再举一个例子:
复制代码
#!/bin/bash
option="${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.sh
test.sh: usage: [ -f filename ] | [ -d directory ]
$ ./test.sh -f index.htm
$ vi test.sh
$ ./test.sh -f index.htm
File name is index.htm
$ ./test.sh -d unix
Dir name is unix
$
复制代码

17. for循环 

  与其余编程语言相似,Shell支持for循环。

  for循环通常格式为:
for 变量 in 列表
do
    command1
    command2
    ...
    commandN
done
  列表是一组值(数字、字符串等)组成的序列,每一个值经过空格分隔。每循环一次,就将列表中的下一个值赋给变量。
  in 列表是可选的,若是不用它,for 循环使用命令行的位置参数。
  例如,顺序输出当前列表中的数字:
for loop in 1 2 3 4 5
do
echo "The value is: $loop"
done
  运行结果:
The value is: 1
The value is: 2
The value is: 3
The value is: 4
The value is: 5
  顺序输出字符串中的字符:
for str in 'This is a string'
do
echo $str
done
  运行结果:
This is a string
  显示主目录下以 .bash 开头的文件:
#!/bin/bash
for FILE in $HOME/.bash*
do
echo $FILE
done
  运行结果:
/root/.bash_history
/root/.bash_logout
/root/.bash_profile
/root/.bashrc

18. while循环

  while循环用于不断执行一系列命令,也用于从输入文件中读取数据;命令一般为测试条件。其格式为:
while command
do
   Statement(s) to be executed if command is true
done
  命令执行完毕,控制返回循环顶部,从头开始直至测试条件为假。
  如下是一个基本的while循环,测试条件是:若是COUNTER小于5,那么返回 true。COUNTER从0开始,每次循环处理时,COUNTER加1。运行上述脚本,返回数字1到5,而后终止。
复制代码
COUNTER=0
while [ $COUNTER -lt 5 ]
do
COUNTER='expr $COUNTER+1'
echo $COUNTER
done
复制代码
运行脚本,输出:
 
  
1
2
3
4
5
  while循环可用于读取键盘信息。下面的例子中,输入信息被设置为变量FILM,按<Ctrl-D>结束循环。
复制代码
echo 'type <CTRL-D> to terminate'
echo -n 'enter your most liked film: '
while read FILM
do
echo "Yeah! great film the $FILM"
done
复制代码
运行脚本,输出相似下面:
type <CTRL-D> to terminate
enter your most liked film: Sound of Music
Yeah! great film the Sound of Music

19. until命令 

  until 循环执行一系列命令直至条件为 true 时中止。until 循环与 while 循环在处理方式上恰好相反。通常while循环优于until循环,但在某些时候,也只是极少数状况下,until 循环更加有用。
  until 循环格式为:
until command
do
   Statement(s) to be executed until command is true
done
  command 通常为条件表达式,若是返回值为 false,则继续执行循环体内的语句,不然跳出循环。
  例如,使用 until 命令输出 0 ~ 9 的数字:
复制代码
#!/bin/bash
a=0
until [ ! $a -lt 10 ]
do
echo $a
a=`expr $a + 1`
done
复制代码
  运行结果:
复制代码
0
1
2
3
4
5
6
7
8
9
复制代码

20. 跳出循环

  在循环过程当中,有时候须要在未达到循环结束条件时强制跳出循环,像大多数编程语言同样,Shell也使用 break 和 continue 来跳出循环。

  20.1 break命令

  break命令容许跳出全部循环(终止执行后面的全部循环)。

  下面的例子中,脚本进入死循环直至用户输入数字大于5。要跳出这个循环,返回到shell提示符下,就要使用break命令。
复制代码
#!/bin/bash
while :
do
echo -n "Input a number between 1 to 5: "
read aNum
case $aNum in
1|2|3|4|5) echo "Your number is $aNum!"
;;
*) echo "You do not select a number between 1 to 5, game is over!"
break
;;
esac
done
复制代码
  在嵌套循环中,break 命令后面还能够跟一个整数,表示跳出第几层循环。例如:
break n
  表示跳出第 n 层循环。
  下面是一个嵌套循环的例子,若是 var1 等于 2,而且 var2 等于 0,就跳出循环:
复制代码
#!/bin/bash
for var1 in 1 2 3
do
for var2 in 0 5
do
if [ $var1 -eq 2 -a $var2 -eq 0 ]
then
break 2
else
echo "$var1 $var2"
fi
done
done
复制代码
如上,break 2 表示直接跳出外层循环。运行结果:
1 0
1 5

  20.2 continue命令

  continue命令与break命令相似,只有一点差异,它不会跳出全部循环,仅仅跳出当前循环。
  对上面的例子进行修改:
复制代码
#!/bin/bash
while :
do
echo -n "Input a number between 1 to 5: "
read aNum
case $aNum in
1|2|3|4|5) echo "Your number is $aNum!"
;;
*) echo "You do not select a number between 1 to 5!"
continue
echo "Game is over!"
;;
esac
done
复制代码
  运行代码发现,当输入大于5的数字时,该例中的循环不会结束,语句
echo "Game is over!"
  永远不会被执行。
  一样,continue 后面也能够跟一个数字,表示跳出第几层循环。
  再看一个 continue 的例子:
复制代码
#!/bin/bash
NUMS="1 2 3 4 5 6 7"
for NUM in $NUMS
do
Q=`expr $NUM % 2`
if [ $Q -eq 0 ]
then
echo "Number is an even number!!"
continue
fi
echo "Found odd number"
done
复制代码
  运行结果:
复制代码
Found odd number
Number is an even number!!
Found odd number
Number is an even number!!
Found odd number
Number is an even number!!
Found odd number
复制代码

21. Shell函数

  函数可让咱们将一个复杂功能划分红若干模块,让程序结构更加清晰,代码重复利用率更高。像其余编程语言同样,Shell 也支持函数。Shell 函数必须先定义后使用。
  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 here
Hello () {
echo "Url is http://see.xidian.edu.cn/cpp/shell/"
}
# Invoke your function
Hello
复制代码
  运行结果:
$./test.sh
Hello World
$
  调用函数只须要给出函数名,不须要加括号。
  再来看一个带有return语句的函数:
复制代码
#!/bin/bash
funWithReturn(){
echo "The function is to get the sum of two numbers..."
echo -n "Input first number: "
read aNum
echo -n "Input another number: "
read anotherNum
echo "The two numbers are $aNum and $anotherNum !"
return $(($aNum+$anotherNum))
}
funWithReturn
# Capture value returnd by last command
ret=$?
echo "The sum of two numbers is $ret !"
复制代码
  运行结果:
The function is to get the sum of two numbers...
Input first number: 25
Input another number: 50
The two numbers are 25 and 50 !
The sum of two numbers is 75 !
  函数返回值在调用该函数后经过 $? 来得到。
  再来看一个函数嵌套的例子:
复制代码
#!/bin/bash
# Calling one function from another
number_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 选项,以下所示:
$unset .f function_name
  若是你但愿直接从终端调用函数,能够将函数定义在主目录下的 .profile 文件,这样每次登陆后,在命令提示符后面输入函数名字就能够当即调用。

22. Shell函数参数 

  在Shell中,调用函数时能够向其传递参数。在函数体内部,经过  nn的形式来获取参数的值,例如,1表示第一个参数,$2表示第二个参数...
  带参数的函数示例:
复制代码
#!/bin/bash
funWithParam(){
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 !"
复制代码
  注意, 1010不能获取第十个参数,获取第十个参数须要{10}。当n>=10时,须要使用${n}来获取参数。
  另外,还有几个特殊变量用来处理参数,前面已经提到:
特殊变量 说明
$# 传递给函数的参数个数。
$* 显示全部传递给函数的参数。
$@ 与$*相同,可是略有区别,请查看Shell特殊变量
$? 函数的返回值。

23. 输入输出重定向

  Unix 命令默认从标准输入设备(stdin)获取输入,将结果输出到标准输出设备(stdout)显示。通常状况下,标准输入设备就是键盘,标准输出设备就是终端,即显示器。

  23.1 输出重定向

  命令的输出不只能够是显示器,还能够很容易的转移向到文件,这被称为输出重定向。
  命令输出重定向的语法为:
$ command > file
  这样,输出到显示器的内容就能够被重定向到文件。
  例如,下面的命令在显示器上不会看到任何输出:
$ who > users
  打开 users 文件,能够看到下面的内容:
复制代码
$ cat users
oko         tty01   Sep 12 07:30
ai          tty15   Sep 12 13:32
ruth        tty21   Sep 12 10:10
pat         tty24   Sep 12 13:07
steve       tty25   Sep 12 13:03
$
复制代码
  输出重定向会覆盖文件内容,请看下面的例子:
$ echo line 1 > users
$ cat users
line 1
$
  若是不但愿文件内容被覆盖,可使用 >> 追加到文件末尾,例如:
$ echo line 2 >> users
$ cat users
line 1
line 2
$

  23.2 输入重定向

  和输出重定向同样,Unix 命令也能够从文件获取输入,语法为:
command < file
  这样,原本须要从键盘获取输入的命令会转移到文件读取内容。
  注意:输出重定向是大于号(>),输入重定向是小于号(<)。
  例如,计算 users 文件中的行数,可使用下面的命令:
$ wc -l users
2 users
$
  也能够将输入重定向到 users 文件:
$ wc -l < users
2
$
注意:上面两个例子的结果不一样:第一个例子,会输出文件名;第二个不会,由于它仅仅知道从标准输入读取内容。

  23.3 重定向深刻讲解

  通常状况下,每一个 Unix/Linux 命令运行时都会打开三个文件:
  • 标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。
  • 标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。
  • 标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。
  默认状况下,command > file 将 stdout 重定向到 file,command < file 将stdin 重定向到 file。
  若是但愿 stderr 重定向到 file,能够这样写:
$command 2 > file
  若是但愿 stderr 追加到 file 文件末尾,能够这样写:
$command 2 >> file
  2 表示标准错误文件(stderr)。

  若是但愿将 stdout 和 stderr 合并后重定向到 file,能够这样写:
$command > file 2>&1
  或
$command >> file 2>&1
  若是但愿对 stdin 和 stdout 都重定向,能够这样写:
$command < file1 >file2
  command 命令将 stdin 重定向到 file1,将 stdout 重定向到 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 中的一种特殊的重定向方式,它的基本的形式以下:
  1. command << delimiter
  2. document
  3. delimiter
  它的做用是将两个 delimiter 之间的内容(document) 做为输入传递给 command。
  注意:
  • 结尾的delimiter 必定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和 tab 缩进。
  • 开始的delimiter先后的空格会被忽略掉。
  下面的例子,经过 wc -l 命令计算 document 的行数:
复制代码
$wc -l << EOF
    This is a simple lookup program
    for good (and bad) restaurants
    in Cape Town.
EOF
3
$
复制代码
  也能够 将 Here Document 用在脚本中,例如:
复制代码
#!/bin/bash
cat << EOF
This is a simple lookup program
for good (and bad) restaurants
in Cape Town.
EOF
复制代码
  运行结果:
This is a simple lookup program
for good (and bad) restaurants
in Cape Town.
  下面的脚本经过 vi 编辑器将 document 保存到 test.txt 文件:
复制代码
#!/bin/sh
filename=test.txt
vi $filename <<EndOfCommands
i
This file was created automatically from
a shell script
^[
ZZ
EndOfCommands
复制代码
  运行脚本:
$ sh test.sh
Vim: Warning: Input is not from a terminal
$
打开 test.txt,能够看到下面的内容:
$ cat test.txt
This file was created automatically from
a shell script
$

  /dev/null 文件

  若是但愿执行某个命令,但又不但愿在屏幕上显示输出结果,那么能够将输出重定向到 /dev/null:
$ command > /dev/null
  /dev/null 是一个特殊的文件,写入到它的内容都会被丢弃;若是尝试从该文件读取内容,那么什么也读不到。可是 /dev/null 文件很是有用,将命令的输出重定向到它,会起到”禁止输出“的效果。
  若是但愿屏蔽 stdout 和 stderr,能够这样写:
$ command > /dev/null 2>&1

 24. 文件包含

  像其余语言同样,Shell 也能够包含外部脚本,将外部脚本的内容合并到当前脚本。
  Shell 中包含脚本可使用:
. filename
  或
source filename
  两种方式的效果相同,简单起见,通常使用点号(.),可是注意点号(.)和文件名中间有一空格。
  例如,建立两个脚本,一个是被调用脚本 subscript.sh,内容以下:
url="http://see.xidian.edu.cn/cpp/view/2738.html"
  一个是主文件 main.sh,内容以下:
#!/bin/bash
. ./subscript.sh
echo $url
  执行脚本:
$chomd +x main.sh
./main.sh
http://see.xidian.edu.cn/cpp/view/2738.html
$
  注意:被包含脚本不须要有执行权限。
相关文章
相关标签/搜索