目录
一、编程语言的分类
编译型语言:C、C++ ------>需要编译器
解释型语言:shell、python ------>需要解析器
二、shell
shell---->贝壳
shell解析器:起到保护内核的作用,用户无法直接和内核层交换,通过指令和shell解析器完成用户和内核的交互
应用层:代码
--------------------------- shell解析器
内核层:
内核层的五大功能:
1、内存管理
2、网络管理
3、进程管理
4、文件管理
5、设备管理
---------------------------
硬件层:外部设备
【1】第一个shell脚本
hello.sh ---->后缀是.sh
#!/bin/bash
# #!---->shebang
# 指明脚本运行使用的shell解析器
#这是一行注释
echo "第一个shell脚本"
【2】常见的shell解析器
bash:现在市面上大部分linux都使用bash解析器
dash:比bash功能更少一点
sh:和终端的交互性不好
csh:类似C语言的模式
如何查看本机使用的shell解析器:echo $SHELL
【3】运行脚本的3种方式
i)bash
bash 文件名.sh ------>使用shell解析器去解析脚本
bash在运行脚本时,会在后台打开一个新的终端,把运行的结果返回到当前终端
ii)source
source是一个终端指令
source 文件名.sh source在同一个终端上运行和输出结果
iii)直接给脚本添加可执行权限
chmod 777 脚本名
./脚本名
三、修改环境变量
【1】如何查看系统提供的环境变量
env ---->回显所有系统提供的环境变量
【2】查看PATH变量
echo $PATH
PATH的作用,在终端执行指令或程序时,默认在PATH包含的路径中查找,如果程序/指令的路径不在PATH中,就会执行失败(未找到该命令)
修改PATH之后,可以直接输入可执行程序名执行程序,不需要再加上路径
【3】修改PATH路径
一定不能修改原有的PATH路径
i)只对当前终端生效
export PATH=${PATH}:新的路径
export PATH=${PATH}:/home/ubuntu/23061/day2
export PATH = ${PATH} : /home/ubuntu/23061/day2
| | | | | |
给(系统)变量赋值 要赋值的变量 赋值 拿到原有的PATH的值 路径分隔符 追加的新路径
ii)只对当前用户生效 ---->修改家目录下的文件
vim ~/.bashrc --->打开用户的配置文件,把想要添加的路径使用export表达式添加到最后一行
让配置文件生效:
- 重启(永久生效)
- source ~/.bashrc (临时生效) ------>使用source和.是同一个指令
- . ~/.bashrc (临时生效)
iii)对所有用户都生效的方式
修改/etc/environment
sudo vim /etc/environment
直接把想添加的路径,添加原有的路径后面
让配置文件生效:
- 重启(永久生效)
- source /etc/environment (临时生效) ------>使用source和.是同一个指令
- . /etc/environment (临时生效)
iv)对所有用户生效
修改/etc/bash.bashrc
sudo vim /etc/bash.bashrc
使用export表达式,将路径添加到最后
让配置文件生效:
- 重启(永久生效)
- source /etc/bash.bashrc (临时生效) ------>使用source和.是同一个指令
- . /etc/bash.bashrc (临时生效)
四、shell中的变量
shell本身是擅长运行指令,shell是一个弱数据类型的语言
【1】定义变量
C中:
存储类型 数据类型 变量名;
shell中:
变量=变量的值 ----->如果变量的值中间没有空格直接使用
变量='变量的值' ----->变量的值中间有空格
变量="变量的值" ----->使用一个已有的变量给新的变量赋值,并且赋值中有空格时
''内,$变量名,不会被展开
注意:
- shell中等号两侧不允许有空格
- 如果有空格会把变量名识别成一个指令
【2】使用变量
在shell中如果使用变量的值,需要给变量名前加$
$变量名 ${变量名}
【3】变量的赋值
1、使用已有的变量给新的变量赋值
var1=hello
var2=world
var3="$var1 $var2"
shell脚本的本质:命令的集合
五、shell中的数组
【1】定义
C中
int arr[4]={1,2,3,4};
shell:
数组名=(1 2 3 4) ----->每个元素之间以空格作为分隔
shell中支持稀疏数组
数组名=([下标]=初始值1 [下标]=初始值2 ·····)
#!/bin/bash
arr=(12 90 89 100)
#shell中支持稀疏数组,下标不连续的数组
brr=([0]=90 [3]=70 [7]=900)
crr[0]=29 #给crr数组中下标为0的元素赋值
crr[3]=78 #给crr数组中下标为3的元素赋值
#再重新给brr中没有提供的下标的元素赋值
brr[4]=67
echo ${brr[4]}
echo ${crr[3]}
【2】数组中元素的访问
${数组名[下标]}
访问数组中的所有元素
${数组名[*]}
${数组名[@]}
${#数组名[*]}
#!/bin/bash
arr=(12 90 89 100)
#shell中支持稀疏数组,下标不连续的数组
brr=([0]=,2 [3]=70 [7]=900)
crr[0]=29 #给crr数组中下标为0的元素赋值
crr[3]=78 #给crr数组中下标为3的元素赋值
#再重新给brr中没有提供的下标的元素赋值
brr[4]=67
echo ${brr[@]}
echo ${crr[*]}
echo ${#brr[*]} #4 对于稀疏数组,#会记录数组中实际元素的个数
echo ${#brr[0]} #2 对数组中的指定元素使用#,#记录元素中字符的个数
练习:
1、定义一个数组,使用外部参数给数组赋值,通过数组求外部参数的个数
2、把家目录的下的所有文件名放到数组中,并记录家目录下文件的个数
#!/bin/bash
arr=($*) #把所有的外部参数赋值给数组arr
echo ${#arr[*]}
arr2=(`ls ~`) #把家目录的所有文件名赋值给数组arr1
echo ${#arr2[*]}
echo ${arr2[@]}
【3】使用已有的数组给新的数组赋值
#!/bin/bash
arr1=(1 2 3 4)
arr2=(b n m l)
#定义一个数组arr3,使用原来的arr1和arr2给新数组arr3赋值
arr3=(${arr1[*]} ${arr2[*]})
echo ${arr3[@]} # 1 2 3 4 b n m l
arr3=(${arr1[*]}${arr2[*]})
echo ${arr3[@]} #1 2 3 4b n m l
echo ${#arr3[*]}
六、shell中的输入输出
【1】输出--->echo
echo默认不解析转义字符并且会自动换行
-e:让echo指令解析转义字符
-n:取消换行
#!/bin/bash
echo "111\n" #echo默认不解析转义字符,会默认换行
echo -e "111\n" #111 换行两次
echo "111\n" -e #111\n -e echo的参数不能放在最后一个位置,被识别成字符串
echo -ne "111\n" #让echo取消换行,-n参数
【2】read
read 变量名
read -s 变量名 ---->输入的内容不回显
read -p "提示信息" 变量名 ----->-p回显提示信息
read -n 字符个数 变量名 ----->控制输入的字符个数,当超过会自动停止
read -t 秒数 变量名 ----->控制读入数据的时间,如果指定时间内不输入会自动停止
read -a 数组名 ---->输入数组
练习:
1、尝试把read除了-a以外的参数结合起来使用
#!/bin/bash
#read -p "请输入一个变量" var
#read -n 3 var
#read -t 3 var
#read -a arr
read -sp "请输入一个变量" -n 3 -t 4 var
#echo ${#arr[*]}
echo $var
七、shell中的算术运算
shell本身不擅长算术运算,需要借助于运算符和其他指令
(()) $[] let expr
【1】(())
常用于shell中整数的算术运算
(())几乎支持所有的C语言语法,支持shell中的幂运算 **
使用方法:
- ((表达式1,表达式2,表达式3,····))每一个表达式都会执行,取到最后一个表达式的结果
- (())内使用变量时,可以加$也可以不加$
- (())内的运算符两侧,可以有空格也可以没有空格
- 变量名=$((表达式)),获取(())的运算结果
- 可以直接在(())内进行赋值操作,((var1 = var1+var2))
练习:
1、终端输入两个三位数,将其中一个自增,把两个变量赋值给第二个变量相加并输出
#!/bin/bash
read -p "请输入两个变量" var1 var2 #如果同一行获取两个变量,变量中间放空格
((var1++)) #自增
((var2=var1+var2))
echo $var1
echo $var2
((var1=var1**3)) #对var1进行幂运算
echo $var1
2、求root用户的uid和ubuntu/linux用户gid相加的结果,比较这两个数的大小关系
#!/bin/bash
num1=`id -u root`
num2=`id -g`
echo $((num1+num2))
#比较num1和num2的大小关系
echo $((num1<num2))
#比较num1和num2的大小关系
echo $((num1<num2?num2:num1))
【2】$[]实现算数运算
使用方法: (仍然支持幂运算和自增自减运算)
- 变量名=$[表达式1,表达式2,表达式3,····],每一个表达式都执行,获取最后一个表达式的结果
- 运算时,运算符两侧可以有空格也可以没有空格
- 使用变量时,可以加$也可以不加$
- $[]本质上会遗留一个计算结果在,运算所在行,可以选择直接echo $[表达式] ,变量名=$[表达式]
#!/bin/bash
num1=100
num2=30
echo $[num1+num2] #直接在终端回显130
echo $[num1++,num2**2,++num2] #31
echo $num1 #101
echo $num2 #31
练习:
1、计算当前目录下文件个数和家目录下文件个数的总和
2、计算家目录下.c和.sh文件的和
#!/bin/bash
arr=(`ls`)
arr1=(`ls ~`)
brr=(`ls` `ls ~`) #把两个路径下的文件,放到同一个数组中
crr=(${arr[*]} ${arr1[*]}) #先把两个路径下的文件分别存在不同数组中,再拼接两个数组
num1=${#arr[*]}
num2=${#arr1[*]}
echo $[num1+num2]
echo ${#brr[*]}
echo ${#crr[*]}
arr3=(`ls ~/*.c`)
arr4=(`ls ~/*.sh`)
#对前两行的数组计数
num3=${#arr3[*]}
num4=${#arr4[*]}
echo $[num3+num4]
【3】let实现算数运算
使用方法:
- let 变量名=表达式 ----->let和变量名中间一定有空格
- let使用变量可以加$,也可以不加$
- let运算时,运算符两侧一定不能有空格
- let 表达式,运算是可以进行的但是没有办法接收运算的结果
#!/bin/bash
num1=100
num2=30
let ret=num2**2 #支持幂运算
let num1++ #支持自增运算,但是不能接收表达式的结果
echo $ret
echo $num1 #101
【4】expr
expr是一条指令
使用方法:
- expr使用变量的值时,必须加$
- 运算符两侧必须加空格 (不支持幂运算和自增自减运算)
- expr在使用时,一些字符需要转义,*,>,
- expr直接回显指令的执行结果到终端
ARG1 | ARG2
如果ARG1的值不为0,结果就是ARG1,否则就是ARG2
ARG1 & ARG2
如果RAG1和ARG2都不为0,结果是ARG1,否则是0
ARG1 < ARG2
ARG1 is less than ARG2
ARG1 <= ARG2
ARG1 is less than or equal to ARG2
ARG1 = ARG2
ARG1 is equal to ARG2
ARG1 != ARG2
ARG1 is unequal to ARG2
ARG1 >= ARG2
ARG1 is greater than or equal to ARG2
ARG1 > ARG2
ARG1 is greater than ARG2
#!/bin/bash
num1=-2
num2=9
: 'expr $num1 + $num2
expr $num1 - $num2
expr $num1 / $num2
expr $num1 % $num2
expr $num1 \* $num2
'
num3=0
expr $num1 \| $num2
expr $num1 \& $num2
expr $num2 \> $num1
expr $num2 != $num1
expr $num2 = $num1
练习:
1、终端读入两个数据,使用expr比较大小关系
2、计算/etc/group中,第20行组用户gid和第10行组用户gid的和
#!/bin/bash
read -p "请输入两个变量" var1 var2
expr $var1 \>= $var2
#获取/etc/group中第20行用户的gid
num1=`head -20 /etc/group | tail -1 | cut -d : -f 3`
#获取/etc/group中第10行用户的gid
num2=$(head -10 /etc/group | tail -1 | cut -d : -f 3)
expr $num1 + $num2
expr对字符串的运算
match str1 str2
返回str2在str1中完全匹配的个数(str2可以作为str1中子串)
substr STRING POS LENGTH
如果字符串长度不够截取长度,就把字符串中所有的内容都截取出来
从string中的第pos个位置开始截取长度为length的子串(pos从1开始)
index STRING CHARS
返回字符在字符串中第一次出现的位置,如果是多个字符,返回最先在字符串中出现的字符的下标
(下标从1开始)
length STRING
求字符串的长度
#!/bin/bash
str1=hello
str2=hl
expr match $str1 $str2 #0,因为hello中不能匹配到hl字符串
expr substr $str1 2 3 #pos计数从1开始
expr index $str1 lo #3l在hello最先出现
expr length $str1
expr length $str2
练习:
1、终端输入网址,如:www.baidu.com,要求:
接触网址每个部分,并放入数组中,不能使用cut,使用expr解决
#!/bin/bash
read -p "请输入一个网址" net
len=`expr length $net` #网址的长度
#找第一个.的位置
pos1=`expr index $net .`
#截取第一个.前面的所有子串
arr[0]=`expr substr $net 1 $((pos1-1))`
#为了找第二个.需要把后面的所有子串都截取出来
str2=`expr substr $net $((pos1+1)) $len`
#找到第二个.的位置
pos2=`expr index $str2 .`
arr[1]=`expr substr $str2 1 $((pos2-1))`
arr[2]=`expr substr $str2 $((pos2+1)) $len`
echo ${arr[*]}
八、shell中的分支语句
【1】if···else分支
[]就是test指令
#单分支结构
if [ test语句 ] -----> if test 表达式
then
语句块
fi
#双分支
if [ test语句 ] -----> if test 表达式
then
语句块
else
条件不成立执行的语句块
fi
#多分支语句
if [ test语句 ] -----> if test 表达式
then
语句块
elif [ test语句 ] ------> elif test 表达式
then
条件不成立执行的语句块
fi
#!/bin/bash
num1=90
num2=300
#if [ $num1 -le $num2 ]
if test $num1 -le $num2
then
echo "num1<=num2"
fi
余下见链接
https://blog.csdn.net/ck0056/article/details/132816564
练习:
写一个1.sh脚本,将以下内容放到脚本中:
在家目录下创建目录文件,dir
在dir下创建dir1和dir2
把当前目录下的所有文件拷贝到dir1中,
把当前目录下的所有脚本文件拷贝到dir2中
把dir2打包并压缩为dir2.tar.xz
再把dir2.tar.xz移动到dir1中
解压dir1中的压缩包
使用tree工具,查看dir下的文件
#!/bin/bash
mkdir ~/dir
mkdir ~/dir/dir2 ~/dir/dir1
cp * ~/dir/dir1/ -r
cp *.sh ~/dir/dir2/
tar -cJf ~/dir/dir2.tar.xz ~/dir/dir2/
mv ~/dir/dir2.tar.xz ~/dir/dir1/
tar -xvf ~/dir/dir1/dir2.tar.xz
tree ~/dir