Shell编程
Shell 既是一种命令语言—交互式的解释和执行用户输入的命令;
又是一种程序设计语言(shell脚本)—可以定义各种变量,传递参数,并提供许多高级语言所具有的流程控制结构。
其不是Linux系统内核的一部分,但它调用了系统内核的大部分功能来执行程序、创建文档并以并行的方式协调各个系统的运行。
Shell的原意为"壳",它包裹在内核之外,处于用户与内核之间。如下图:
Shell 主要功能为接收用户输入的命令,找到命令所在位置,执行。所以可以把Shell看出内核外的命令接口,或者用户的命令解释器。(从图中可以看出Shell是个中介。)
1、Shell概述
1.1 shell 分类
很多
查看系统中安装的全部shell命令
ls /bin/*sh
查看某个shell的版本号,例如 Bash Shell
/bin/bash --version
1.2 shell功能
Linux 系统中所有可执行文件都可以在Shell中执行。
Linux中5类可执行文件 :
- Linux命令
- 内置命令
- 实用程序
- 用户程序
- Shell脚本
1.3 shell命令执行过程
在查找外部命令时有两种情况:1)若给出用户路径,则按照给出的路径查找。2)若用户未给出路径,则在环境变量$PATH所指定的路径中查找。
环境变量PATH的信息可以使用下面命令查看,注意大写PATH:
echo $PATH
2 shell 技巧
2.1 输入输出重定向
- 输入重定向
输入重定向运算符“ < ”,指定右值为左值的输入
命令<文件名
- 输出重定向
输出重定向运算符“ > ”,指定右值为左值的输出
命令>文件名
(追加用 >>)
例如:
cat file1 > file # 清空file中的内容,file1中内容覆盖
cat file2 >> file # file2中内容追加到file1后面
- 错误重定向
命令 2>文件名
注意:
- 在错误重定向中使用了标准错误文件的编号2。其实在输入/输出重定向中,也可以添加相应对应的文件编号,如下:
命令 0 < 文件名
命令 1 > 文件名
命令 1 >> 文件名
只是当标准输入、标准输出的文件编号出现在重定向的左侧时,可以被省略。
- 掌握“&”运算符----表示 “等同于”
eg: 2>&1 : 将标准错误的输出重定向到指定的标准输入输出文件。若在此之前,标准输出文件已经被修改,则命令执行过程中的错误不会输入到默认的标准输出文件,而是输出到当前指定的标准输出文件。
如下:
标准输出已经重定向到空设备文件,因此标准错误输出也重定向到空设备文件。
1 > /dev/null
2 > &1
2.2 管道
可以将简单的命令连接起来,使一个命令的输出作为另外一个命名的输入,由此实现更加复杂的功能。符号:" | ".
命令1 | 命令2 | 命令...
2.3 命令连接符
- ;连接符
命令按照先后次序执行 - &&连接符
前面命令执行成功,后面的才执行 - ||连接符
前面命令执行失败,后面的才执行
2.4 文本提取器命令
不懂
awk
3 shell编程
注意的细节:
- 单引号中间的变量会被视为字符串,不能够被解析
- 变量定义,等号两侧不能有空格
- if中的test命令[],在使用时,距离两个中括号内侧都要有空格
- 在脚本中使用 expr 命令,要用 tab上面的反引号括起来,不是单引号。
执行shell
1)chmod +x 文件名
./文件名
2)sh 文件名
3.1 shell中的变量及基本操作
# 定义变量
var='hello'
# 使用变量,加{}是良好的编程习惯
$var
${var}
# 返回变量长度
${#var}
# 从命令行读取数据,即用户交互输入
read 变量名
# 位置变量
$0 :脚本的名称
$1 :脚本的第一个参数
$2 :脚本的第二个参数
$# : 传递到脚本的参数量,这里是2个
# 运算
let
expr
- let
let命令可以进行算术运算和数值表达式测试。
let 表达式
在脚本中使用,我目前在终端直接运行没有结果输出:
脚本如下:
#!/bin/bash
i=1
echo "i="$i
let i=i+2
echo "i="$i
let "i=i+4"
echo "i="$i
echo "*************"
((i+=3))
echo "i="$i
exit 0
运行结果,根据结果可以看出,let命令可以直接使用,或者在双引号之间也可以使用。
chmod ./let
./let
let命令也可以使用 (()) 替代, 根据上述脚本
((算术表达式))
(如果运行时出现找不到let,脚本文件的首行 修改成其他解释器)
- expr
操作符和数据之间需要用空格,可以直接在终端使用
[user]$ expr 2 + 2
4
在脚本中使用 expr 命令,要用 tab上面的反引号括起来,不是单引号。
#!/bin/bash
a=10
b=20
value=`expr $a + $b `
echo "value is $value"
exit 0
结果
value is 30
3.2 if语句
条件判断:
test 命令:
test 选项 参数
检查文件是否存在:
if test -f file
then
...
fi
test命令可以使用 命令 [ 来替代,两者都可以起到判断作用。
if [ -f file ]
then
...
fi
[ 命令也是命令,命令与选项及参数之间应有空格。
因此在 [] 符号与其中的条件检查之间需要留出空格,否则将会产生错误。
#!/bin/bash
# 单分支if语句
read filename
if [ -d $filename ]
then
echo $filename "是个目录"
fi
# 双分支语句
read filename2
if [ -d $filename2 ]
then
echo $filename2"是个目录"
else
echo $filename2"不是目录"
fi
# 多分支if语句
read filename3
if [ -d $filename3 ]
then
ls $filename3
elif [ -x $filename ];then
echo "这是一个可执行文件"
else
echo "该文件不可执行"
fi
exit 0
3.3 select语句
可以将列表做出类似目录的形式,以交互的形式选择在列表中的数据。break是跳出
#!/bin/bash
echo "what you want to choice"
select subject in "C++" "C" "java"
do
echo "you have select $subject"
break
done
exit 0
结果
what you want to choice
1) C++
2) C
3) java
#? 2 # 我输入的
you have select C
3.4 case语句
将一个变量的内容与多个选项进行匹配,匹配成功,则执行相关语句;
每个匹配条件以 ;; 结尾相当于 break
最后一个匹配项 * ,类似于C语言中的default,是一个通配符,该匹配项末尾不需要 ;;
#!/bin/bash
echo -e "a:\c"
read a
echo -e "b:\c"
read b
echo -e "select(+-):\c"
read var
case $var in
'+')echo "a+b="`expr $a + $b` ;;
'-')echo "a-b=" `expr $a - $b ` ;;
*)echo "error"
esac
exit 0
结果
a:2
b:3
select(+-*/):-
a-b= -1
a:2
b:3
select(+-*/):0
error
(-e 表示开启转义;输出的内容末尾添加了 \c 表示输出内容之后不换行)
3.5 for 循环
# for 循环格式
for 变量 in 变量列表
do
...
done
注意:变量列表中的每个变量可以使用引号单独引起来,但是不能将整个列表置于一对引号中,这样会被视为一个变量。
示例:
#!/bin/bash
for month in 1 2 3 4 5 6
do
echo -e "$month\t\c"
done
echo
exit 0
结果:
1 2 3 4 5 6
3.6 while循环
# while 格式
while [ 表达式 ]
do
...
done
示例:
#!/bin/bash
count=1
sum=0
while [ $count -le 100 ]
do
sum=`expr $sum + $count`
count=`expr $count + 1`
done
echo "sum=$sum"
exit 0
结果:
sum=5050
3.7 until 循环
until循环与while循环的格式基本相同,不同的是
当until循环的条件为假的时候,才继续执行循环中的命令。
示例: -gt 大于
#!/bin/bash
i=1
until [ $i -gt 3 ]
do
echo "the number is $i"
i=` expr $i + 1 `
done
exit 0
结果:
the number is 1
the number is 2
the number is 3
3.8 脚本调试
shell脚本中常用的调试选项
- -n 不执行脚本,仅仅检查脚本中的语法问题
- -v 在执行脚本的过程中,将执行过的脚本命令打印到屏幕
- -x 将用到的脚本内容打印到屏幕上
利用刚刚的./until举例
3.9 shell中函数
格式:
[function] 函数名 [()] {
代码段
[return int]
}
调用需要在函数定义之前,因为shell脚本逐行执行。
#!/bin/bash
function hello() {
echo "hello function"
}
# main
hello
exit 0
结果
hello function