0.shell是一个什么东西?
shell是一个命令解析器
我们可以把很多要执行的命令,以某种语言的方式,组织起来
交给shell去解析执行
这种命令的组织方式 ->shell脚本语言。
shell脚本的文件后缀名 .sh
xxx.sh 是多个命令的组织文件,shell脚本文件也是一种普通文件,
是以shell脚本语言的方式,语法把多条命令语句组织起来
./xxx.sh 把这些命令交给shell命令解析器,去执行
命令解析器其实就是一个程序:
/bin/bash
/bin/sh
/bin/dash
....
都是shell解析程序
1.shell脚本文件
一个最简单的shell脚本文件:
vim hello.sh
-------------------------
#!/bin/bash
#! 指定shell的解析程序/告诉系统其后路径所指定的程序即是解释此脚本文件的shell程序。
echo "hello shell" // echo命令:用于向窗口输出文本。
-------------------------
修改脚本的权限
chmod +x hello.sh
运行脚本文件
./hello.sh
2.shell变量
在shell脚本文件里面,也是可以定义变量
shell变量没有类型的概念,全部都是字符串
shell变量没有类型,说明咱们就可以直接用,无需定义。
注意,变量名与等号之间不能有空格
变量名的命名规则
1.命名只能使用英文字母,数字,下划线,首个字符不能以数字开头
2.中间不能有空格
3.不能使用标点符号
4.不能使用bash里的关键字
变量名=值
name=value
引用变量:引用变量的值// 使用一个定义过的变量,只要在变量名前面加 ”$“(美元符号)
$变量名
${变量名}
例子:test1.sh
val=sb250
echo $val
echo ${val}
注意:‘=’赋值符号的两边都不能有空格
shell变量有四种:
(1)自定义变量
如:
val=sb250
(2)位置变量
指的是传递给脚本文件或函数的参数
如:
./test1.sh 123 456 abc
在shell脚本或shell函数中:
$0 ->第0个参数,命令行程序名(./test1.sh)
$1,$2....$9 表示第一个到第九个参数的名字
$# -> 表示命令行参数的个数(不包括./test.sh)
$@ -> 表示命令行所有的参数(不包括$0)
$@ <==> "$1","$2"
$* ->包括所有命令行的参数
$* <=> $1c$2c$3c....
c:内部域分隔符(默认是空格或换行)
$? ->表示前面的那一个命令或程序的退出码(返回值)main函数的返回值
练习:
test2.sh
写一个shell脚本,把脚本的参数的个数,以及每一个参数都打印出来
#!/bin/bash
echo $#
echo $0
echo $@
(3)环境变量
环境变量:
在同一终端下面所有的进程都可以共享变量
HOME : 用户主目录的路径
如:
echo $HOME
===>/home/china
PATH: 命令或可执行程序的搜索路径
问题:
ls 命令在哪个地址都可以直接执行,然而我们并没有去执行的路径
PATH:指定系统要搜索的命令或可执行程序的路径列表
echo $PATH
=> dir1:dir2:dir3:......
如何修改环境变量的值:
export 环境变量名=新值
export PATH=$PATH:/home/china
如果你想要配置的环境变量在所有的终端都生效:
修改配置文件: /etc/profile
在这个文件的末尾,加一行:
export PATH=$PATH:/home/china
步骤:
a,以管理员权限打开 /etc/profile
sudo vi /etc/profile
b,将光标移到文件的末尾,然后进入输入模式
i/I a/A o/O
c,将export PATH=$PATH:/home/china添加到本文件中去
重启之后生效
(4)特殊变量
略
3.shell数组
a,定义数组以及初始化
数组名=(1 2 3 4 5 6)
例子:
arr=(1 2 3 4 5 6)
b, 引用数组元素
${数组名[下标]}
${数组名} or ${数组名[0]} or $数组名 ==>引用数组的第0个元素
c,引用整个数组
${数组名[*]}
${数组名[@]}
求数组元素个数:
${#数组名[*]}
${#数组名[@]}
练习:
定义一个数组,并且初始化。
打印数组中的所有元素值,还有元素个数
#!/bin/bash
arr=(1 2 3 4 5 6)
echo ${arr[*]}
echo ${#arr[*]}
4.shell语句
4.1说明性语句(注释)
以#开始的,就是注释行
4.2功能性语句
如:
任意操作系统的命令:
ls \ echo \ cd \ date \......
shell名义,自编程序
read :在shell中表示是从终端获取输入
例子:
test4.sh
#!/bin/bash
read val1 val2
v1=$val1
v2=$val2
echo $v1
echo $v2
上述例子从终端获取两个字符串,第一个字符串保存在变量val1中,
第二个字符串保存在val2中。
重定向的问题:
(1)输入重定向
命令的输入请求通常是向标准输入设备(键盘,终端)提出请求,
我们也可以很方便的把输入重新定向为一个文件,这种情况,我们称之为“输入重定向”
在命令后面添加 < filename
该命令所有的输入都来自于filename 所指向的那个文件中的内容
例子:
./test4.sh < 1.txt
(2)输出重定向
输出某个内容时,一般是将内容输出到终端,也可以方便的将要输出的内容
输出到一个文件中去,这种操作我们就叫做“输出重定向”
在命令后面添加 > filename
在命令后面添加 >> filename
> : 会先清空filname的内容,然后再输出到文件中去
>> : 追加,把输出的内容添加到filename 指定的文件的下一行。
expr : 算术运算命令
主要是用于进行简单的整数的运算
包含: + - / \* %
例子:
expr 5 + 3
val=`expr 5 + 3`
注意:操作数与操作符,前后至少要有一个空格
``反撇号,引用里面的那个命令或执行程序或脚本的输出结果
DATE=`date`
例子:
read i j
ret=`expr $i + $j`
echo $ret
练习:写一个脚本,计算两个整数的积,两个整数都需要通过文件传入(输入重定向)
test; test语句可以用来测试三种对象
a, 字符串测试
= 测试两个字符串内容是否完全一直
例子:
test "abc" = "abc"
echo $? #0 表示成功
!= 测试两个字符串内容是否不一致
例子:
test "abc" != "abc"
echo $? #1 表示失败
-z zero 测试字符串是否为空
test -z ""
echo $? #0
-n not null 测试字符串是否不为空
test -n ""
echo $? #1
b, 整数测试
a,b表示两个整数
a -eq b :equal 测试两个整数是否相等
例子:
test 3 -eq 4
echo $? #1
a -ne b : not equal 不等于 “!=”
例子:
test 3 -ne 4
echo $? #0
a -gt b: greater than 大于“>”
a -ge b: greater equal 大于等于 “>=”
a -lt b: little than 小于“<”
a -le b: little equal 小于等于"<="
c,文件测试
-d filename :测试filename是否为一个目录(dir)
-f filename :测试filename是否为一个普通文件(file)
-l filename :测试filename是否为一个链接文件(link)
-r filename :测试filename是否存在并且可读
-w filename :测试filename是否存在并且可写
-x filename :测试filename是否存在并且可执行
-s filename :测试filename是否存在并且长度不为0
filename1 -nt filename2:测试文件1是否比文件2更新
-nt newer than
filename1 -ot filename2: 测试文件1是否比文件2更旧
-ot older than
最后,test命令可以用[ ]来简写
例子:
test $i -eq $j
<==> [ $i -eq $j ]
test 复合表达式
组合了两个或两个以上的表达式,称之为"复合表达式",
为了使用复合表达式,可以用:
(1)test([ ])内置的操作
test expr1 "符号" expr2
"符号" :test 内置的操作符
-a :and 并且
-o :or 或者
例子:
5 > 4 > 3
test 5 -gt 4 -a 4 -gt 3
<===>
[ 5 -gt 4 -a 4 -gt 3 ]
(2)直接使用c语言中的逻辑运算符来操作
-a &&
-o ||
例子:
5 > 4 > 3
test 5 -gt 4 && test 4 -gt 3
<==>
[ 5 - gt 4 ] && [ 4 - gt 3 ]
echo $? #0
4.3结构性语句
顺序结构
分支结构
循环结构
a, 分支结构
if cmd ; then
#.....
fi
-----------------
if cmd ; then
#......
else
#......
fi
-----------------
if cmd ; then
#......
else
if cmd2 ; then
#......
else
#......
fi
fi
练习:
从键盘输入一个整数,判断这个整数是否为奇数。
read var
ret=`expr $var % 2`
if [ $ret -eq 0 ] ; then
echo "偶数"
else
echo "奇数"
fi
b,多路分支语句
case 字符串变量 in
模式1)
........ ;; #;;类似于在c语言中的break,但是在shell变成了;; 一定要有
模式2)
.........;;
.....
模式n)
.........;;
esac
case语句真正强大的地方在于它可以使用模式而不是固定的字符串来进行操作
一个模式是由一串正则表达式或特殊的通配符组成的字符串。
这些模式可以由正则表达式来描述
c,循环语句
for 变量名 in 单词表
do
#循环体语句
done
单词表 :以空白符隔开的字符串列表
如:
abc a b c mmm
for 执行的次数就是“单词表”中单词的个数
每次执行时,“变量”的值就是取下一个对应的那一个单词的值。
例子:
for i in abc a b c mmm
do
echo $i
done
=>
abc
a
b
c
mmm
-----------------------------
for 可以写出和c语言类似的风格
for(( i=1 ; i<=100 ; i++ ))
练习 : 0-100求和
sum=0
for((i=1 ; i<=100 ; i++))
do
sum=`expr $sum + $i`
done
echo $sum
练习: 用shell求出100以内3的倍数之和。
......
--------------------------------
while 命令或表达式
do
#循环体语句
done
练习: 0-100求和
sum=0
i=0
while [ $i -le 100 ]
do
sum=`expr $sum + $i`
i=`expr $i + 1`
done
echo $sum
---------------------------------
until 命令或表达式
do
#循环体语句
done
until和while 的功能时类似的,不同之处在于
until只有当测试的命令或表达式的值为假的时候,才执行循环体语句。
当条件成立,退出循环
例子:
求1-100求和
sum=0
i=0
until [ $i -gt 100 ]
do
sum=`expr $sum + $i`
i=`expr $i + 1`
done
echo $sum
--------------------------------
break 和continue
break n :
跳出第n层循环
n 表示数字,代表第几层循环
continue n:
结束本次循环,跳转到最近的第n层下面去继续下一轮循环。
break 和 continue 后面的n可不可以不加呢?
可以,如果没有n,那么他的含义是和c语言中的含义一样
练习:
1.从键盘输入一个数,判读这个整数是否为质数
read n
flag=1 #是质数
i=2
while [ $i -le `expr $n / 2`]
do
if[ `expr $n % $i` -eq 0 ] ; then
#不是质数
flag=0
#如何提前结束循环?
break
fi
i=`expr $i + 1`
done
if [ $flag -eq 1 ] ; then
echo "$n is prime"
else
echo "$n is not prime"
fi
5.shell 函数
func_name()
{
.........
}
func_name :自定义的函数名,名字取法与c语言中是一样的。
例子:
sum()
{
a=$1
b=$2
s=`expr $a + $b`
return $s
}
调用:
sum 5 6
函数调用:
func_name arg1 arg2 arg3 ......
在函数内部:
arg1 -> $1
arg2 -> $2
arg3 -> $3
....
....
函数返回值的获取
func_name arg1 arg2 arg3 ......
ret=$?
$? 永远都是最近的一个命令或一个程序的退出码
func_name 最后一个命令或表达式的返回值
就是最后用return语句返回的内容