一、shell 简介
Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。
Shell 既是一种命令语言,又是一种程序设计语言。
Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。1.Shell 脚本
Shell 脚本(shell script),是一种为 shell 编写的脚本程序。 
什么是脚本语言?
脚本语言是像剧本一样教计算机办某个事情的语言,
这类程序可以用文本编辑器修改,不需要编译,通常是解释运行的。2.Shell 环境
Linux 的 Shell 种类众多,常见的有:
Bourne Shell(/usr/bin/sh或/bin/sh)
Bourne Again Shell(/bin/bash)
C Shell(/usr/bin/csh)
K Shell(/usr/bin/ksh)
Shell for Root(/sbin/sh)
…… 
Bash(Bourne Again Shell)是日常工作中使用最广泛的,也是大多数Linux 系统默认的 Shell。
在一般情况下,并不区分 Bourne Shell 和 Bourne Again Shell,
所以,像 #!/bin/sh,它同样也可以改为 #!/bin/bash。
#! 告诉系统其后路径所指定的程序即是解释此脚本文件的 Shell 程序。3.第一个shell脚本
打开文本编辑器(可以使用 vi/vim 命令来创建文件),
新建一个文件 hello.sh,扩展名为 sh(sh代表shell),扩展名并不影响脚本执行。
cat > hello.sh <<!
实例
#!/bin/bash
 echo "Hello World !" 
#! 是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种 Shell。
echo 命令用于向窗口输出文本。 4.运行 Shell 脚本有两种方法:
4.1 作为可执行程序
将上面的代码保存为 hello.sh,并 cd 到相应目录:
  chmod u+x ./hello.sh     #使脚本具有执行权限
  ./hello.sh              #执行脚本
注意,一定要写成 ./hello.sh,而不是 hello.sh,运行其它二进制的程序也一样,
直接写 hello.sh,linux 系统会去 PATH 里寻找有没有叫 hello.sh 的,
而只有 /bin, /sbin, /usr/bin,/usr/sbin 等在 PATH 里,
当前目录通常不在 PATH 里,所以写成 hello.sh 是会找不到命令的,
要用 ./hello.sh 告诉系统说,就在当前目录找。 4.2 作为解释器参数
这种运行方式是,直接运行解释器,其参数就是 shell 脚本的文件名,如: 
/bin/sh hello.sh
这种方式运行的脚本,不需要在第一行指定解释器信息,写了也没用。 二、shell变量
1.定义变量
your_name="lw"
注意:变量名和等号之间不能有空格。
变量名的命名须遵循如下规则: 
  首个字符必须为字母(a-z,A-Z)。
  中间不能有空格,可以使用下划线(_)。
  不能使用标点符号。
  不能使用bash里的关键字(可用help命令查看保留关键字)。2.使用变量
使用一个定义过的变量,只要在变量名前面加美元符号即可,如:
your_name="lw"
echo $your_name
例子:
cat > your_name.sh <<!
#!/bin/bash
your_name="lw"
echo $your_namechmod u+x ./your_name.sh     #使脚本具有执行权限
./your_name.sh              #执行脚本变量名外面的花括号是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界.
echo ${your_name}
已定义的变量,可以被重新使用:
#!/bin/bash
your_name="lw"
echo ${your_name}
your_name="alibaba"
echo ${your_name}3.只读变量
使用 readonly 命令可以将变量定义为只读变量,只读变量的值不能被改变。
尝试更改只读变量,结果报错:your_name: 只读变量
#!/bin/bash
your_name="lw"
echo ${your_name}
readonly your_name 
your_name="alibaba"
echo ${your_name}4.删除变量
使用 unset 命令可以删除变量。语法:
unset variable_name
变量被删除后不能再次使用。unset 命令不能删除只读变量。#!/bin/bash
your_name="lw"
echo ${your_name}
#readonly your_name 
unset your_name 
echo ${your_name}5.变量类型
运行shell时,会同时存在三种变量:
5.1 局部变量 
     局部变量在脚本或命令中定义,仅在当前shell实例中有效,
     其他shell启动的程序不能访问局部变量。
5.2 环境变量 
     所有的程序,包括shell启动的程序,都能访问环境变量,
     有些程序需要环境变量来保证其正常运行。
     必要的时候shell脚本也可以定义环境变量。
5.3 shell变量 
     shell变量是由shell程序设置的特殊变量。
     shell变量中有一部分是环境变量,有一部分是局部变量,
     这些变量保证了shell的正常运行6.Shell 字符串
字符串是shell编程中最常用最有用的数据类型(数字和字符串),
字符串可以用单引号,也可以用双引号,也可以不用引号。
6.1 单引号 
your_name='lw'
单引号字符串的限制: 
单引号里的任何字符都会原样输出,
单引号字符串中的变量是无效的;
单引号字串中不能出现单引号(对单引号使用转义符后也不行)。6.2 双引号 
双引号的优点:
双引号里可以有变量
双引号里可以出现转义字符
cat > your_name3.sh <<!
#!/bin/bash
your_name='lw'
echo "hello,${your_name}!"
#echo "Hello, \"$your_name\"! \n"6.3 拼接字符串 
6.4 # 获取字符串长度 
cp your_name3.sh your_name4.sh#!/bin/bash
your_name="lw"
string=hello
echo $string $your_name
echo ${#string}
echo ${#your_name}6.5 : 提取子字符串 
从字符串第 2 个字符开始截取 4 个字符:
#!/bin/bash
string="hello lw!"
echo ${string:1:4}     # 输出 ello6.6 查找子字符串 
查找字符 "e" 的位置:
#!/bin/bash
string="hello lw!"
echo `expr index "$string" e`   # 输出 2
注意: 以上脚本中 "`" 是反引号,而不是单引号 "'".
cp your_name4.sh your_name5.sh
vi your_name5.sh
#!/bin/bash
string="hello lw!"
echo ${string:1:4} 
echo `expr index "$string" e`7.Shell 注释
以"#"开头的行就是注释,会被解释器忽略。
每一行加一个#号可以注释一行;
sh里没有多行注释,可以把这一段要注释的代码用一对花括号括起来,
定义成一个函数,没有地方调用这个函数,这块代码就不会执行,达到了和注释一样的效果。 8.字符串截取的八种方法:
假设有变量 var=http://www.aaa.com/123.htm	
8.1 从左边第几个字符开始,及字符的个数
echo ${var:0:5}
其中的 0 表示左边第一个字符开始,5 表示字符的总个数。
结果是:http:8.2 从左边第几个字符开始,一直到结束。
echo ${var:7}
其中的 7 表示左边第8个字符开始,一直到结束。
结果是 :www.aaa.com/123.htm

8.3 从右边第几个字符开始,及字符的个数
echo ${var:0-7:3}
其中的 0-7 表示右边算起第七个字符开始,3 表示字符的个数。
结果是:1238.4 从右边第几个字符开始,一直到结束。
echo ${var:0-7}
表示从右边第七个字符开始,一直到结束。
结果是:123.htm
注:(左边的第一个字符是用 0 表示,右边的第一个字符用 0-1 表示)#、## 表示从左边开始删除。
  一个 # 表示从左边删除到第一个指定的字符;
  两个 # 表示从左边删除到最后一个指定的字符。
%、%% 表示从右边开始删除。
  一个 % 表示从右边删除到第一个指定的字符;
  两个 % 表示从右边删除到最后一个指定的字符。
删除包括了指定的字符本身。

8.5 # 号截取,删除左边字符,保留右边字符。 
echo ${var#*//}
其中 var 是变量名,# 号是运算符,*// 表示从左边开始删除第一个 // 号及左边的所有字符
即删除 http://
echo ${var#*/}
结果是 :/www.aaa.com/123.htm8.6 ## 号截取,删除左边字符,保留右边字符。
echo ${var##*/}
##*/ 表示从左边开始删除最后(最右边)一个 / 号及左边的所有字符
即删除 http://www.aaa.com/
结果是 123.htm8.7 %号截取,删除右边字符,保留左边字符
echo ${var%/*}
%/* 表示从右边开始,删除第一个 / 号及右边的字符
结果是:http://www.aaa.com8.8 %% 号截取,删除右边字符,保留左边字符
echo ${var%%/*}
%%/* 表示从右边开始,删除最后(最左边)一个 / 号及右边的字符
结果是:http:三、shell传递参数
1.传递参数
在执行 Shell 脚本时,向脚本传递参数,脚本内获取参数的格式为:$n。
n 代表一个数字,1 为执行脚本的第一个参数,2 为执行脚本的第二个参数,以此类推……
cp your_name.sh  parameter.sh
#!/bin/bash
echo "hello $1";
调用: ./parameter.sh  lw2.参数处理
$#      传递到脚本的参数个数 
$*      以一个单字符串显示所有向脚本传递的参数,以"$1 $2 … $n"的形式输出所有参数。 
$@    与$*相同,但是使用时加引号(如"$@"),并在引号中返回每个参数"$1“ ”$2“ … ”$n"。
$* 与 $@ 区别:
相同点:都是引用所有参数。
不同点:只有在双引号中体现出来。
假设在脚本运行时写了三个参数 1、2、3,,
则 " * " 等价于 "1 2 3"(传递了一个参数),
而 "@" 等价于 "1" "2" "3"(传递了三个参数)。 
cp prameter.sh prameter2.sh
#!/bin/bash
echo "$1";
echo "$2";
echo "$#";
echo $*;
for i in "$*"; do
    echo $i
done
echo "$@";
for i in "$@"; do
    echo $i
done
调用: ./prameter2.sh  lw 1123 null四、shell 运算符
shell运算符分为6类,包括:
算术运算符
关系运算符
布尔运算符
逻辑运算符
字符串运算符
文件测试运算符原生bash不支持简单的数学运算,但是可以通过expr命令来实现。 
expr 是一款表达式计算工具,使用它能完成表达式的求值操作。 
例如,两个数相加(注意使用的是反引号 ` 而不是单引号 '):
#!/bin/bash
val=`expr 2 + 2`
echo "两数之和为 : $val"
两点注意:
表达式和运算符之间要有空格,例如 2+2 是不对的,必须写成 2 + 2。
完整的表达式要被 ` ` 包含,注意这个字符不是常用的单引号,在 Esc 键下边。1.算术运算符
下表列出了常用的算术运算符,假定变量 a 为 10,变量 b 为 20:
+    加法    `expr $a + $b`   结果为 30。 
-     减法    `expr $a - $b`    结果为 -10。 
*     乘法    `expr $a \* $b`   结果为  200。  乘号(*)前边必须加反斜杠(\)才能实现乘法运算
/     除法    `expr $b / $a`    结果为 2。 
%    取余    `expr $b % $a`  结果为 0。 
在 MAC 中 shell 的 expr 语法是:$((表达式)),此处表达式中的 "*" 不需要转义符号 "\" 。=    赋值     a=$b               将把变量 b 的值赋给 a。 
==   相等。     用于比较两个数字,相同则返回 true。     [ $a == $b ] 返回 false。 
!=    不相等。  用于比较两个数字,不相同则返回 true。 [ $a != $b ] 返回 true。 
注意:条件表达式要放在方括号之间,并且要有空格,
例如: [$a==$b] 是错误的,必须写成 [ $a == $b ]。算术运算符实例如下:
#!/bin/bash
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 等于 b";
elfi [ $a != $b ]
then
   echo "a 不等于 b"
fi#!/bin/bash
a=10;
b=20;
echo "a+b= $((a+b))";
echo "a-b= $((a-b))";
echo "a*b= $((a*b))";
echo "b/a= $((b/a))";
echo "a%3= $((a%3))";2.关系运算符
关系运算符只支持数字,不支持字符串,除非字符串的值是数字。
下表列出了常用的关系运算符,假定变量 a 为 10,变量 b 为 20:
-eq  == 检测两个数是否相等,相等返回 true。                               [ $a -eq $b ] 返回 false。 
-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。 eq 就是 equal等于
ne 就是 not equal不等于 
gt 就是 greater than大于  
lt 就是 less than小于 
ge 就是 greater than or equal 大于等于 
le 就是 less than or equal 小于等于关系运算符实例如下:
#!/bin/bash
a=10;
b=20;
if [ $a -eq $b ]
then
   echo "$a -eq $b : a 等于 b"
else
   echo "$a -eq $b: a 不等于 b"
fi
if [ $a -ne $b ]
then
   echo "$a -ne $b: a 不等于 b"
else
   echo "$a -ne $b : a 等于 b"
fi
if [ $a -gt $b ]
then
   echo "$a -gt $b: a 大于 b"
else
   echo "$a -gt $b: a 不大于 b"
fi
if [ $a -lt $b ]
then
   echo "$a -lt $b: a 小于 b"
else
   echo "$a -lt $b: a 不小于 b"
fi
if [ $a -ge $b ]
then
   echo "$a -ge $b: a 大于或等于 b"
else
   echo "$a -ge $b: a 小于 b"
fi
if [ $a -le $b ]
then
   echo "$a -le $b: a 小于或等于 b"
else
   echo "$a -le $b: a 大于 b"
fi3.布尔运算符
下表列出了常用的布尔运算符,假定变量 a 为 10,变量 b 为 20:
!    非运算,表达式为 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。 布尔运算符实例如下:
#!/bin/bash
a=10
b=20
if [ $a != $b ]
then
   echo "$a != $b : a 不等于 b"
else
   echo "$a != $b: a 等于 b"
fi
if [ $a -lt 100 -a $b -gt 15 ]
then
   echo "$a 小于 100 且 $b 大于 15 : 返回 true"
else
   echo "$a 小于 100 且 $b 大于 15 : 返回 false"
fi
if [ $a -lt 100 -o $b -gt 100 ]
then
   echo "$a 小于 100 或 $b 大于 100 : 返回 true"
else
   echo "$a 小于 100 或 $b 大于 100 : 返回 false"
fi
if [ $a -lt 5 -o $b -gt 100 ]
then
   echo "$a 小于 5 或 $b 大于 100 : 返回 true"
else
   echo "$a 小于 5 或 $b 大于 100 : 返回 false"
fi4.逻辑运算符
以下介绍 Shell 的逻辑运算符,假定变量 a 为 10,变量 b 为 20:
&&  逻辑的 AND   [[ $a -lt 100 && $b -gt 100 ]] 返回 false 
||      逻辑的 OR      [[ $a -lt 100 || $b -gt 100 ]] 返回 true 逻辑运算符实例如下:
#!/bin/bash
a=10
b=20
if [[ $a -lt 100 && $b -gt 100 ]]
then
   echo "返回 true"
else
   echo "返回 false"
fiif [[ $a -lt 100 || $b -gt 100 ]]
then
   echo "返回 true"
else
   echo "返回 false"
fi5.字符串运算符
下表列出了常用的字符串运算符,假定变量 a 为 "abc",变量 b 为 "efg":
=    检测两个字符串是否相等,相等返回 true。        [ $a = $b ] 返回 false。 
!=   检测两个字符串是否不相等,不相等返回 true。 [ $a != $b ] 返回 true。 
-z   检测字符串长度是否为0,为0返回 true。           [ -z $a ] 返回 false。 
-n   检测字符串长度是否不为0,不为0返回 true。    [ -n $a ] 返回 true。 
str   检测字符串是否不为空,不为空返回 true。        [ $a ] 返回 true。 字符串运算符实例如下:
#!/bin/bash
a="abc"
b="efg"
if [ $a = $b ]
then
   echo "$a = $b : a 等于 b"
else
   echo "$a = $b: a 不等于 b"
fi
if [ $a != $b ]
then
   echo "$a != $b : a 不等于 b"
else
   echo "$a != $b: a 等于 b"
fi
if [ -z $a ]
then
   echo "-z $a : 字符串长度为 0"
else
   echo "-z $a : 字符串长度不为 0"
fi
if [ -n $a ]
then
   echo "-n $a : 字符串长度不为 0"
else
   echo "-n $a : 字符串长度为 0"
fi
if [ $a ]
then
   echo "$a : 字符串不为空"
else
   echo "$a : 字符串为空"
fi6.文件测试运算符
文件测试运算符用于检测 Unix 文件的各种属性。 
属性检测描述如下:
-b file    检测文件是否是块设备文件,如果是,则返回 true。              [ -b $file ] 返回 false。 
-c file    检测文件是否是字符设备文件,如果是,则返回 true。           [ -c $file ] 返回 false。 
-d file    检测文件是否是目录,如果是,则返回 true。                        [ -d $file ] 返回 false。 
-f file     检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true。     [ -f $file ] 返回 true。 
-p file    检测文件是否是有名管道,如果是,则返回 true。                    [ -p $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。 
-g file    检测文件是否设置了 SGID 位,如果是,则返回 true。             [ -g $file ] 返回 false。
-k file    检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true。 [ -k $file ] 返回 false。 
-u file    检测文件是否设置了 SUID 位,如果是,则返回 true。              [ -u $file ] 返回 false。 
变量 file 表示文件"/var/www/a.txt",具有 rwx 权限。
下面的代码,将检测该文件的各种属性:
#!/bin/bash
file="/home/lw/a.txt"
if [ -r $file ]
then
   echo "文件可读"
else
   echo "文件不可读"
fi
if [ -w $file ]
then
   echo "文件可写"
else
   echo "文件不可写"
fi
if [ -x $file ]
then
   echo "文件可执行"
else
   echo "文件不可执行"
fi
if [ -f $file ]
then
   echo "文件为普通文件"
else
   echo "文件为特殊文件"
fi
if [ -d $file ]
then
   echo "文件是个目录"
else
   echo "文件不是个目录"
fi
if [ -s $file ]
then
   echo "文件不为空"
else
   echo "文件为空"
fi
if [ -e $file ]
then
   echo "文件存在"
else
   echo "文件不存在"
fi