shell简介
何为shell
shell是用户与操作系统之间的接口,可以解析并执行用户输入,然后返回用户结果的解析程序。与GUI类似,只不过GUI是图形化的更容易被人们使用,而shell是命令行形式的,需要用户输入指令。shell编程指的是shell脚本编程。
shell种类
-
Bourne Shell(/usr/bin/sh或/bin/sh)
-
Bourne Again Shell(/bin/bash)
-
C Shell(/usr/bin/csh)
-
...
查看当前shell类型
[root@hangzhou01 ~]# echo $SHELL
/bin/bash
变量
变量范围
局部变量:只在创建该变量的shell生效
全局变量:在创建该变量的shell和从该shell派生出来的子shell生效,通过export关键字标志
变量类型
shell编程中最常用的类型是字符串和数组
字符串
shell的字符串既可以使用单引号,也可以使用双引号
-
单引号内的内容会直接输出,双引号内的内容有变量会解析变量
-
单引号的限制:单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;
test.sh脚本
#!/bin/sh
city="北京";
echo "中国首都是$city"
echo "中国首都是"$city""
echo "中国首都是'$city'"
echo '中国首都是$city'
echo '中国首都是"$city"'
echo '中国首都是'$city'' --第一个为'中国首都是' 和 $city 和 '', 所以解析了变量
[root@hangzhou01 ~]# ./test.sh
中国首都是北京
中国首都是北京
中国首都是'北京'
中国首都是$city
中国首都是"$city"
中国首都是北京
验证:
[root@hangzhou01 ~]# city="北京";
[root@hangzhou01 ~]# echo $city'1001'
北京1001
[root@hangzhou01 ~]# echo $city"1001"
北京1001
[root@hangzhou01 ~]# echo $city1001
[root@hangzhou01 ~]#
- 字符串长度
- 截取子字符串
#!/bin/sh
str="student of beijing";
echo ${#str}
echo ${str:3:4}
[root@hangzhou01 ~]# ./test1.sh
18
dent
数组
shell仅支持一维数组,且未限定数组大小
- 定义
数组名=(值1 值2 ... 值n)
##赋值方式一
arr=(1,2,3,4,5,6)
##赋值方式二
arr[0]=1
arr[1]=2
arr[2]=3
arr[3]=4
arr[4]=5
arr[5]=6
- 读取
${数组名[下标]}
##读取一个值
${arr[5]}
##读取整个数组
${arr[@]}
- 获取长度
##获取数组的长度
${#arr[@]}
##获取数组某个值的长度
${#arr[5]}
传递参数
脚本支持传递参数,在脚本内怎样获取参数呢?
$0 --脚本名称,包括脚本路径
$n --获取第n个参数,n>=1,1表示第一个参数,2表示第二个参数...
$@ --获取所有参数
$# --参数个数
$? --最后命令的退出状态。0表示没有错误,其他任何值表明有错误。
test2.sh
#!/bin/bash
echo "脚本路径:$0"
echo "第一个参数:$3"
echo "第二个参数:$2"
echo "第三个参数:$3"
echo "所有参数:$@"
echo "参数个数:$#"
echo "最后一条指令执行状态:$?"
[root@hangzhou01 ~]# ./test2.sh 101 102 103
脚本路径:./test2.sh
第一个参数:103
第二个参数:102
第三个参数:103
所有参数:101 102 103
参数个数:3
最后一条指令执行状态:0
运算符
算术运算符、关系运算符、布尔运算符、字符串运算符、文件测试运算符
算术运算符
shell不支持简单的算术运算符,需要借助expr等其它工具来实现
加法 `expr a + b`
减法 `expr a - b`
乘法 `expr a \* b` --注意:乘法需要使用反斜杠才能实现
除法 `expr a / b`
test3.sh
#!/bin/bash
echo `expr $1 + $2`
echo `expr $1 - $2`
echo `expr $1 \* $2`
echo `expr $1 / $2`
[root@hangzhou01 ~]# ./test3.sh 10 9
19
1
90
1
这种更好用,推荐:$((表达式))
[root@hangzhou01 ~]# echo $((6+4))
10
[root@hangzhou01 ~]# echo $((6-4))
2
[root@hangzhou01 ~]# echo $((6*4))
24
[root@hangzhou01 ~]# echo $((6/4))
1
[root@hangzhou01 ~]# echo $((6%4))
2
关系运算符
关系运算符表达式需要使用[ ]包裹使用,表示检查的表达式是否为真。关系运算符只支持数字,不支持字符串,除非字符串的值是数字。
-eq 检查相等
-ne 检查不相等
-gt 检查左边大于右边
-lt 检查左边小于右边
-ge 检查左边大于等于右边
-le 检查左边小于等于右边
test4.sh
#!/bin/bash
if [ $1 -eq $2 ];then
echo "$1与$2相等"
fi
if [ $1 -ne $2 ];then
echo "$1与$2不相等"
fi
if [ $1 -gt $2 ];then
echo "$1大于$2"
fi
if [ $1 -lt $2 ];then
echo "$1小于$2"
fi
if [ $1 -ge $2 ];then
echo "$1大于等于$2"
fi
if [ $1 -le $2 ];then
echo "$1小于等于$2"
fi
[root@hangzhou01 ~]# ./test4.sh 1 9
1与9不相等
1小于9
1小于等于9
[root@hangzhou01 ~]# ./test4.sh 9 9
9与9相等
9大于等于9
9小于等于9
[root@hangzhou01 ~]# ./test4.sh 20 9
20与9不相等
20大于9
20大于等于9
布尔运算符
! 取反
-o 或
-a 与
test5.sh
#!/bin/bash
if [ $1 -eq 5 ];then
echo '$1 -eq 5为真'
fi
if [ ! $1 -eq 5 ];then
echo '! $1 -eq 5为真'
fi
if [ $1 -eq 5 -o $2 -eq 6 ];then
echo '$1 -eq 5 -o $2 -eq 6为真'
fi
if [ $1 -eq 5 -a $2 -eq 6 ];then
echo '$1 -eq 5 -a $2 -eq 6为真'
fi
[root@hangzhou01 ~]# ./test5.sh 5 5
$1 -eq 5为真
$1 -eq 5 -o $2 -eq 6为真
[root@hangzhou01 ~]# ./test5.sh 6 5
! $1 -eq 5为真
[root@hangzhou01 ~]# ./test5.sh 5 6
$1 -eq 5为真
$1 -eq 5 -o $2 -eq 6为真
$1 -eq 5 -a $2 -eq 6为真
字符串运算符
= 检查字符串相等
!= 检查字符串不相等
-z 检查字符串长度为0
-n 检查字符串长度不为0
$ 检查字符串为为空
test6.sh
#!/bin/bash
if [ $1 = $2 ];then
echo '$1 = $2为真'
fi
if [ $1 != $2 ];then
echo '$1 != $2为真'
fi
if [ -z $1 ];then
echo '-z $1为真'
fi
if [ -n $1 ];then
echo '-n $1为真'
fi
if [ $1 ];then
echo '$1为真'
fi
[root@hangzhou01 ~]# ./test6.sh abc abcd
$1 != $2为真
-n $1为真
$1为真
[root@hangzhou01 ~]# ./test6.sh abc abc
$1 = $2为真
-n $1为真
$1为真
文件运算符
-d 检测文件是否是目录,如果是,则返回 true。
-f 检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true。
-r 检测文件是否可读,如果是,则返回 true。
-w 检测文件是否可写,如果是,则返回 true。
-x 检测文件是否可执行,如果是,则返回 true。
-s 检测文件是否为空(文件大小是否大于0),不为空返回 true。
-e 检测文件(包括目录)是否存在,如果是,则返回 true。
test7.sh
#!/bin/bash
if [ -f $1 ];then
echo "$1是文件"
fi
if [ -d $1 ];then
echo "$1是目录"
fi
if [ -r $1 ];then
echo "$1可读"
fi
if [ -w $1 ];then
echo "$1可写"
fi
if [ -x $1 ];then
echo "$1可执行"
fi
if [ -s $1 ];then
echo "$1不为空"
fi
if [ -e $1 ];then
echo "$1存在"
fi
yaya.txt不为空,yaya1.txt为空文件,first为目录
[root@hangzhou01 ~]# ./test7.sh yaya.txt
yaya.txt是文件
yaya.txt可读
yaya.txt可写
yaya.txt不为空
yaya.txt存在
[root@hangzhou01 ~]# ./test7.sh yaya1.txt
yaya1.txt是文件
yaya1.txt可读
yaya1.txt可写
yaya1.txt存在
[root@hangzhou01 ~]# ./test7.sh first/
first/是目录
first/可读
first/可写
first/可执行
first/不为空
first/存在
流程控制
if
##if 语句语法格式:
if condition
then
command1
command2
...
commandN
fi
##if-else 语句语法格式:
if condition
then
command1
command2
...
commandN
else
command
fi
##if else-if else 语句语法格式:
if condition1
then
command1
elif condition2
then
command2
else
commandN
fi
test8.sh
#!/bin/bash
if [ $1 -lt 100 ];then
echo "if 小于100"
fi
if [ $1 -lt 100 ];then
echo "if-else 小于100"
else
echo "if-else 大于等于100"
fi
if [ $1 -lt 100 ];then
echo "if-else if-else 小于100"
elif [ $1 -eq 100 ];then
echo "if-else if-else 等于100"
else
echo "if-else if-else 大于100"
fi
[root@hangzhou01 ~]# ./test8.sh 99
if 小于100
if-else 小于100
if-else if-else 小于100
[root@hangzhou01 ~]# ./test8.sh 100
if-else 大于等于100
if-else if-else 等于100
[root@hangzhou01 ~]# ./test8.sh 199
if-else 大于等于100
if-else if-else 大于100
[root@hangzhou01 ~]# ./test8.sh 200
if-else 大于等于100
if-else if-else 大于100
[root@hangzhou01 ~]# ./test8.sh 299
if-else 大于等于100
if-else if-else 大于100
case
case 值 in --模式里面的;;不可少,表示跳出case,即最多只能匹配一个模式;如果模式为*,表示匹配所有值
模式1)
command1
command2
...
commandN
;;
模式2)
command1
command2
...
commandN
;;
esac
test13.sh
#!/bin/bash
case $1 in
1) echo $1;
;;
2) echo $1;
;;
3) echo $1;
;;
4) echo $1;
;;
5) echo $1;
;;
6) echo $1;
;;
*) echo "默认匹配:$1";
esac
[root@hangzhou01 ~]# ./test13.sh 5
5
[root@hangzhou01 ~]# ./test13.sh 9
默认匹配:9
for
for var in item1 item2 ... itemN --in的内容用空格隔开,in是可选的,如果无in,则for循环使用命令行的位置参数
do
command1
command2
...
commandN
done
test9.sh
#!/bin/bash
for item in I am a student
do
echo $item
done
[root@hangzhou01 ~]# ./test9.sh
I
am
a
student
test10.sh
#!/bin/bash
for item
do
echo $item
done
[root@hangzhou01 ~]# ./test10.sh 121 222 323 424 525
121
222
323
424
525
while
while condition --用于不断执行一系列命令
do
command
done
while read line--用于从输入文件中读取数据
do
command
done < 文件路径
test11.sh
#!/bin/bash
count=1;
while [ $count -le 100 ]
do
count=`expr $count + 20`
echo $count
done
[root@hangzhou01 ~]# ./test11.sh
21
41
61
81
101
test12.sh
#!/bin/bash
while read line
do
echo $line
done < ./input.txt
[root@hangzhou01 ~]# ./test12.sh
I am a student ha ha!
I am in Beijing.
Chinese is good.
break和continue
break跳出循环
continue跳出本层循环
函数
定义
先定义后使用
[ function ] funname [()]
{
action;
[return int;]
}
--参数返回,可以显示加:return返回,return后跟数值n(0-255)。如果不加,将以最后一条命令运行结果,作为返回值。
调用函数
- 无参调用
test14.sh
#!/bin/bash
function myPrint(){
echo "输出了OK"
}
myPrint
echo $?
[root@hangzhou01 ~]# ./test14.sh
输出了OK
0
test15.sh
#!/bin/bash
function myPrint(){
echo "输出了OK"
return 107
}
myPrint
echo $?
[root@hangzhou01 ~]# ./test15.sh
输出了OK
107
-
传参调用
调用函数时可以向其传递参数。在函数体内部,通过 1表示第一个参数,@、$*等其他的位置参数
test16.sh #!/bin/bash function myPrint(){ echo "输出第一个参数:2" } myPrint 2
[root@hangzhou01 ~]# ./test16.sh 中国 北京 输出第一个参数:中国 输出第二个参数:北京
--请注意函数体里面的位置参数与函数体外面位置参数的区别
重定向
核心概念
一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件:
- 标准输入文件(stdin):文件描述符为0,Unix程序默认从stdin读取数据。
- 标准输出文件(stdout):文件描述符为1,Unix程序默认向stdout输出数据。
- 标准错误文件(stderr):文件描述符为2,Unix程序会向stderr流中写入错误信息。
默认情况下,command > file 将 stdout 重定向到 file,command < file 将stdin 重定向到 file。
输出重定向
用指定的输出文件来替换标准输出或者标准错误输出。有一个特殊的输出文件/dev/null ,如果重定向到该文件,则表明遗弃输出。
command > file 将命令输出从标准输出以覆盖方式重定向到 file
command >> file 将命令输出从标准输出以追加方式重定向到 file
n>&m 将文件描述符n重定向到文件描述符m
who >file 标准输出重定向到file,等价于who 1>file
who >>file
who 2>file 标准错误输出重定向到file
who 2>>file
who >>file 2>>fileErr 标准输出重定向到file,标准错误输出重定向到fileErr
who >>file 2>>&1 标准输出重定向到file,标准错误输出重定向到标准输入 --建议使用
who >>file 2>>file 标准输出重定向到file,标准错误输出重定向file --不建议使用,会打开两次file
输入重定向
用指定的输入文件来替换标准输入
command < file 将标准输入重定向file