Linux_(3)Shell编程(上)

一、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_name

chmod 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"! "

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} # 输出 ello

6.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 表示字符的个数。
结果是:123

8.4 从右边第几个字符开始,一直到结束。
echo ${var:0-7}
表示从右边第七个字符开始,一直到结束。
结果是:123.htm
注:(左边的第一个字符是用 0 表示,右边的第一个字符用 0-1 表示)

#、## 表示从左边开始删除。
一个 # 表示从左边删除到第一个指定的字符;
两个 # 表示从左边删除到最后一个指定的字符。
%、%% 表示从右边开始删除。
一个 % 表示从右边删除到第一个指定的字符;
两个 % 表示从右边删除到最后一个指定的字符。
删除包括了指定的字符本身。

8.5 # 号截取,删除左边字符,保留右边字符。
echo ${var#*//}
其中 var 是变量名,# 号是运算符,*// 表示从左边开始删除第一个 // 号及左边的所有字符
即删除 http://
echo ${var#*/}
结果是 :/www.aaa.com/123.htm

8.6 ## 号截取,删除左边字符,保留右边字符。
echo ${var##*/}
##*/ 表示从左边开始删除最后(最右边)一个 / 号及左边的所有字符
即删除 http://www.aaa.com/
结果是 123.htm

8.7 %号截取,删除右边字符,保留左边字符
echo ${var%/*}
%/* 表示从右边开始,删除第一个 / 号及右边的字符
结果是:http://www.aaa.com

8.8 %% 号截取,删除右边字符,保留左边字符
echo ${var%%/*}
%%/* 表示从右边开始,删除最后(最左边)一个 / 号及右边的字符
结果是:http:

三、shell传递参数
1.传递参数
在执行 Shell 脚本时,向脚本传递参数,脚本内获取参数的格式为:$n。
n 代表一个数字,1 为执行脚本的第一个参数,2 为执行脚本的第二个参数,以此类推……
cp your_name.sh parameter.sh
#!/bin/bash
echo "hello $1";
调用: ./parameter.sh lw

2.参数处理
$# 传递到脚本的参数个数
$* 以一个单字符串显示所有向脚本传递的参数,以"$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"
fi

3.布尔运算符
下表列出了常用的布尔运算符,假定变量 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"
fi

4.逻辑运算符
以下介绍 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"
fi

if [[ $a -lt 100 || $b -gt 100 ]]
then
echo "返回 true"
else
echo "返回 false"
fi

5.字符串运算符
下表列出了常用的字符串运算符,假定变量 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 : 字符串为空"
fi

6.文件测试运算符
文件测试运算符用于检测 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

原文地址:https://www.cnblogs.com/BradMiller/p/9279967.html