语言可以分为两类 编译型语言(C/C++) 以及解释型语言(shell,python,js)。同时shell是一个命令解析器(程序),可以解析用户的输入,交给操作系统内核执行,并且把结果反馈给用户,本身也是一个程序我们可以把很多需要执行的命令(操作),以一种语言的方式组织起来,交给SHELL去运行(解析)
shell脚本的解释器程序
cat /etc/shells
# /etc/shells: valid login shells
/bin/sh
/bin/bash <---------
/bin/rbash
目录
一、shell是什么?
1 写一个简单的脚本文件
2 shell中的变量的使用
3.shell数组
4.shell中的语句
4.1说明性语句
4.2功能性语句
4.2.1.输入重定向
4.2.2.输出重定向
4.2.3.命令中的管道用法
expr:执行算术运算符命令
test:测试语句
a.字符串测试
b.整数测试
c.文件测试
4.3结构性语句(分支语句/循环语句)
a.分支语句
b.多路分支语句(switch)
c.循环语句
for循环
while循环
until循环
d.break和continue
5.shell中的函数
5.1自定义函数的语法:
5.2 函数的返回值的获取,通常有两种方式:
5.2.1.通过反撇号获取命令/函数的执行结果
5.2.2.使用位置变量$?
shell脚本文件要以.sh结尾,其内容多为:
#!/bin/bash
echo "hello shell"
第一行都是固定的: #!/bin/bash
指定由/bin目录下面的哪一个解释器来解析这个脚本文件
脚本中以#开头的行是注释(第一行除外)
shell脚本是不需要编译的,可以直接解释运行,但是需要可执行权限
chmod +x 01.sh
对于一个基础SHELL脚本文件要学习的语法有:
1、变量的使用
2、数组的使用
3、语句(表达式/分支/循环)
4、函数
shell变量没有类型的概念,都是字符串,变量也不需要定义,可以直接使用,shell变量一般有三种
自定义变量、位置变量、环境变量。
格式为:变量名=值 #=两边不能有空格
name=zhangsan
x=123
x=abc
...
如何引用变量:
$变量名 or ${变量名}
三种变量具体如下:
1.自定义变量(自己定义的变量)
例如:
name=zhangsan
x=123
x=abc
...
shell中可以使用普通的shell命令
d=`date` 反撇号(esc的下面)
作用:引用反撇号里面那一个“变量/命令/程序”的输出结果(原先输出到标准输出的内容)
shell中的变量都是字符串,可以直接写到一起,表示连接
2.位置变量
相当于C语言里面main函数的argc和argv
指的是传递给脚本的参数或者传递给函数的参数,参数是按照传递位置排列的
如:
./01sh 123 abc 456
123 abc 456 就是传递给脚本的参数
$0 第0个参数,命令行的程序名称(./01sh)
$1,$2,$3....${10} 表示第一个到第10个参数
$# 表示命令行参数的个数(不包括脚本的名称)
$@ 表示所有的命令行参数(一个列表)
$@ =======> "$1" "$2" "$3" ....
$* 表示所有的命令行参数(一个数据)
$* =======> "$1 $2 $3 ...."
$? 表示前一个命令/函数/程序的退出码(返回值)
3.环境变量
shell解释器可以引用一些外部的变量(不需要定义,可以直接使用)
如:
HOME : 用户的家目录的路径
....
需要重点记住的:
LD_LIBRARY_PATH 动态库的搜索路径
PATH 命令或者可执行程序的搜索路径
有没有发现一个问题?
ls也是一个程序,cd也是一个程序,自己编译出来的a.out也是一个程序
为什么我们在运行ls和cd的时候,不需要指定路径,系统就可以找到这个程序并且运行,而我们自己写的a.out就必须指定路径,否则找不到程序
shell会自动到指定的路径下面去查找你输入的命令,如果找到了就执行,如果找不到就报错
"路径":PATH
echo $PATH
结果/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:
/bin:/usr/games:/usr/local/games:/usr/local/arm/5.4.0/usr/bin:
/snap/bin
指定了系统要搜索的命令和可执行文件的目录列表
PATH:dir1:dir2:.....
我们也可以修改PATH的值,修改环境变量都是使用export
格式:export 环境变量的名称=值
如:
export PATH=$PATH:/mnt/hgfs/CS2406F/2024-1-15Linux基础/code
export WC=wangcai
如果是在终端输入,只对当前终端有效,终端关闭之后,环境变量的值就失效了
如果你想要环境变量永久有效,直接写入到系统的配置文件:
1. ~/.bashrc
此配置只对当前用户有效
每一次打开终端都会执行这个脚本文件,只需要把export那一句加入到文件的后面就可以了
2. /etc/profile
此配置只对所有用户有效,每一次开机都会执行这个脚本文件
3. /etc/environment <--------
此配置只对所有用户有效
shell数组和c语言中数组类似。同样不需要定义,可以直接使用,不能一次性赋值
用法:
数组名[下标]=value
下标:0,1,2,3,4,5....n-1
引用方式:
${数组名[下标]}
引用数组中所有的元素:
${数组名[*]}
${数组名[@]}
引用数组的第一个元素:
${数组名}
例如:
#!/bin/bash
a[0]=1
a[1]=2
a[3]=abc
a[4]=456
echo ${a}
echo ${a[1]}
echo ${a[*]}
echo ${a[@]}
read var1 var2 < 1.txt
echo $var1
echo $var2
i=6
ret=`expr $i + 5 \* 3`
echo $ret
以#开头的行是说明性语句(注释),第一行除外 。
功能性语句指的是一般任意的shell命令(如:ls echo cd date ...),自己写的程序
上面两种可以直接运行,也可以使用反撇号获取结果
shell内部的命令(read,expr,test....)
read:在shell中表示从终端获取输入,保存到指定的变量
如:
read var1 var2
从终端获取两个变量,第一个保存在var1中,第二个保存在var2中
输入----->键盘(标准输入)
输出----->终端/控制台(标准输出)
输入和输出可以重定向到指定的位置
命令的输入请求通常是向标准输入设备(键盘)提交请求
我们也可以很方便的把输入重定向到一个文件,这种情况叫做输入重定向
方法:
在该命令后面添加 < filename
该命令的所有输入都来自于filename指定的文件
命令(程序)的输出通常是提交到标准输出文件(终端/控制台)
我们也可以很方便的把输出重定向到一个文件,这种情况叫做输出重定向
方法:
在命令的后面添加 > filename
or
在命令的后面添加 >> filename
>:会清空原先1.txt的内容,然后把命令的输出内容写入到1.txt文件
>>:追加输出,不会清空原先1.txt的内容,把命令的输出内容写入到1.txt文件的后面
|
用法:
命令1 | 命令2
命令1的输出内容作为命令2的输入
如:
grep -nar main 查找当前目录中所有文件有main的行
grep -nar int 查找当前目录中所有文件有int的行
grep -nar main | grep int
如:
awk -F: '{print $1}' /etc/passwd
#在所有用户中查找名字叫做china的用户的UID
awk -F: '{print $1 $3}' /etc/passwd | grep china
-F:指定列的分隔符
$1:是分隔符分割之后的第一个字段(列)
/etc/passwd 你要处理的文件名
'{print $1}' 你要执行的动作
expr主要用来进行简单的整数运算
+ - * / %
如:
expr 5 + 3 (运算符两边,前后至少一个空格)
计算5+3的结果输出到标准输出
expr 5 - 3
expr 5 \* 3 *在shell中是一个通配符
expr 5 / 3
expr 5 % 3
也可以把计算之后的结果赋值给指定的变量
ret=`expr 5 + 3`
i=6
ret=`expr $i + 5 \* 3`
test语句可以测试三种对象字符串 整数 文件
测试两边的字符串内容是否完全相同
=的两边至少要有一个空格
如:
test "abc" = "abc"
echo $? 获取上一次命令的结果
结果:
相等结果为0
不相等结果为1
可以比较两个变量是否相同
str1=abc
str2=abc
test $str1 = $str2
echo $?
如果比较的时候,有一个字符串为空,就会出现语法错误
str1=abc
str2=
test $str1 = $str2
echo $?
小技巧:
str1=abc
str2=
test ${str1}a = ${str2}a
echo $?
!= 测试两个字符串的内容是否不相同
不相同返回0,相同返回1
test "abc" != "abc"
echo $?
-z zero测试字符串是否为空
为空就返回0
test -z ${str2}
符合你描述的条件,返回0,不符合你描述的条件,就返回1
#-eq equal 测试两个整数是否相等,相等返回0
test 3 -eq 4
echo -eq:$? #1
var1=123
var2=123
test $var1 -eq $var2
echo -eq:$? #0
#-ne not equal 测试两个整数是否不相等,不相等返回0
test 3 -ne 4
echo -ne:$? #0
test $var1 -ne $var2
echo -ne:$? #1
#-gt greate than 测试一个整数是否大于另一个整数
test 3 -gt 4
echo -gt:$? #1
var1=123
var2=12
test $var1 -gt $var2
echo -gt:$? #0
#-ge greate and equal 测试一个整数是否大于等于另一个整数
test 3 -ge 4
echo -ge:$? #1
var1=123
var2=123
test $var1 -ge $var2
echo -ge:$? #0
#-lt little than 测试一个整数是否小于另一个整数
test 3 -lt 4
echo -lt:$? #0
var1=123
var2=12
test $var1 -lt $var2
echo -lt:$? #1
#-le little and equal 测试一个整数是否小于等于另一个整数
test 3 -le 4
echo -le:$? #0
var1=123
var2=12
test $var1 -le $var2
echo -le:$? #1
-d filename 测试filename是否为一个目录文件(directory)
-f filename 测试filename是否为一个普通文件
-L filename 测试filename是否为一个链接文件
-p filename 测试filename是否为一个管道文件
-s filename 测试filename是否为一个socket文件
-c filename 测试filename是否为一个字符设备文件
-b filename 测试filename是否为一个块设备文件
test -d $1
echo $?
-r filename 测试filename是否可读
-w filename 测试filename是否可写
-x filename 测试filename是否可执行
test -r filename
echo $?
test file1 -nt file2 newer than
测试file1是否修改时间在file2的后面
test file1 -ot file2 old than
测试file1是否修改时间在file2的前面
最后test命令可以使用[]来缩写
test Expression <=========> [ Expression ]
如:
[ $str1 = $str2 ]
echo $?
[ 和 ] 两边都必须有空格
test的复合表达式
相当于C语言的逻辑表达式(&& || )
组合了两个或者两个以上的表达式叫做复合表达式
使用方式:
可以使用test内置的操作符来创建复合表达式
test Expression1 "操作符" Expression2
操作符:
-a and 并且
全部满足才返回0
-o or 或者
任意一个满足就返回0
如:
测试..是否为目录的同时,测试位置变量$1和$2是否相等
test -d ".." -a $1 -eq $2
echo $?
===========>
[ -d ".." -a $1 -eq $2 ]
echo $?
相当于C语言中的if语句
语法:
if command; then
语句列表
fi #表示if语句结束
-----------------------
if command; then
语句列表1
else
语句列表2
fi #表示if语句结束
如:
read var1
if [ `expr $var1 % 2` -eq 0 ]
then
echo 偶数!
else
echo 奇数!
fi
例如:
#!/bin/bash
read var1
if [ `expr $var1 % 2` -eq 0 ]
then
echo 偶数!
else
echo 奇数!
fi
echo byebye
语法:
case 变量 in
模式1)
...
;; #类似于C语言中的break,但是在shell中;;不能省略
模式2)
...
;;
模式n)
...
;;
esac #表示case语句结束
case语句还有一个强大的功能在于可以使用"模式/规则"进行匹配而不是固定的字符串来匹配
一个模式是由一串正常的字符串和特殊的通配符组成的字符串(可以是正则表达式)
* 在shell中表示任意多个任意字符(可以是0个)
? 在shell中表示任意一个字符
例如:
read var2
case $var2 in
a | b )
echo "input is a or b"
;; #类似于C语言中的break,但是在shell中;;不能省略
c )
echo "input is c"
;;
d )
echo "input is d"
;;
[0-9]) #正则表达式
echo "input is digtal"
;;
*xx) #通配符,表示任何以xx结尾的东西
echo "input is xxx"
;;
x?x) #通配符
echo "input is yyyy"
;;
语法:
for 变量名 in 单词表(列表)
do
循环体语句
done
单词表:以空格隔开的列表
如:
ls的输出结果
a b c d e f g h
shell中的数字
....
for循环的循环次数就是"单词表"中的单词的个数,并且每一次执行的时候,变量的值就是取单词表中的一个单词
for var in a b c d e f g
do
echo $var
echo -------
done
for var in `ls`
do
echo $var
echo -------
done
for也可以写成C语言的风格
如:计算1~100的和
sum=0
for((i=0;i<=100;i++)) #C语言风格的for循环
do
sum=`expr $sum + $i`
done
echo sum=$sum
语法:
while 命令或者表达式
do
循环体语句
done
命令或者表达式经常是test取测试一个条件
sum=0
i=0
while [ $i -le 100 ]
do
sum=`expr $sum + $i`
i=`expr $i + 1`
done
echo sum=$sum
sum=0
i=0
while((i<=100))
do
sum=`expr $sum + $i`
i=`expr $i + 1`
done
echo sum=$sum
until 条件(命令/表达式)
do
循环体语句
done
until和while语句的功能类似,不同的是,while只有当测试条件满足的时候,进入循环
而until只有当测试条件不满足的时候,才进入循环,条件满足则退出循环,这一点刚好和while相反
sum=0
i=0
until [ $i -gt 100 ]
do
sum=`expr $sum + $i`
i=`expr $i + 1`
done
echo until_sum=$sum
sum=0
i=0
until ((i>100))
do
sum=`expr $sum + $i`
i=`expr $i + 1`
done
echo until2_sum=$sum
break n
跳出第n层循环(c语言中只能跳出当前循环)
continue n
转到第n层循环语句开始执行下一次循环
数字n表示,第几层循环
break和continue后面也可以不加n,不加n表示的含义和C语言一样
function_name()
{
函数内部的命令列表
}
function_name:你自定义的函数的函数名,名字的取法和C语言类似(标识符)
函数不要写参数,如果有参数就是使用"位置变量"
函数定义之后不会自动执行,需要调用才会执行
函数的调用语法:
function_name arg1 arg2 arg3 ....
在函数的内部
arg1 ------> $1
arg2 ------> $2
....
ret=`function_name arg1 arg2`
反撇号是获取函数function_name执行时输出到标准输出的内容
把原本输出到终端的所有的输出都赋值给变量ret
sum()
{
s=`expr $1 + $2`
echo $s
}
echo start
ret=`sum 123 456`
echo stop
echo $ret
$?表示的是上一条命令或者程序的退出码(函数的返回值)
sum2 123 132
结果是sum2最后一个命令或者表达式的值
(在函数里面使用return返回你要返回的值)数字不能超过255
sum2()
{
s=`expr $1 + $2`
echo $s
return $s
}
echo start
sum2 123 132
echo $?
echo stop