【Linux】Linux学习(四)Shell编程

Shell概述

Shell是一个命令行解释器,它能接收应用程序/用户命令,然后调用操作系统内核。
同时Shell还是一门功能相当强大的编程语言,易编写、易调试、灵活性强。

  • Linux 提供的Shell解析器如下:

  • bash和sh的关系

  • Centos默认的解析器是bash

Shell脚本入门

  • 脚本格式

脚本以#!/bin/bash开头(指定解析器)

  • 第一个Shell脚本:helloworld.sh

需求:创建一个Shell脚本,输出helloworld

案例实操:

在helloworld.sh中第一行输入#!/bin/bash,第二行输入echo "hello,world"

脚本的常用执行方式

第一种:采用bash或者sh加上脚本的绝对路径或者相对路径
使用命令 sh 脚本绝对路径

使用命令sh 脚本相对路径

使用命令bash 脚本绝对路径

使用命令bash 脚本相对路径

第二种:采用输入脚本的绝对路径或相对路径执行脚本(必须具有可执行权限+x)
使用相对路径

使用绝对路径

注意:第一种执行方法,本质上是bash解释器帮你执行脚本,所以脚本本身不需要执行权限。第二种执行方法,本质是脚本需要自己执行,所以需要执行权限。

第三种:在脚本路径前加上" . " 或者 source
使用绝对路径

使用相对路径

前两种方式都是在当前 shell 中打开一个子 shell 来执行脚本内容,当脚本内容结束,则子 shell 关闭,回到父 shell 中。
第三种,也就是使用在脚本路径前加“.”或者 source 的方式,可以使脚本内容在当前shell 里执行,而无需打开子 shell!这也是为什么我们每次要修改完/etc/profile 文件以后,需要 source 一下的原因。
开子 shell 与不开子 shell 的区别就在于,环境变量的继承关系,如在子shell 中设置的当前变量,父 shell 是不可见的。

变量

变量存放在内存中,随着变量个数的增加所占用的内存就越大。可以使用unset 变量名删除变量。
当终端关闭时,由于变量存放在内存中,当前终端下自定义变量也会被删除。

系统预定义变量

  • 常用系统变量

$HOME、$PWD、$SHELL、$USER等等

  • 案例实操

使用命令echo $USER查看系统变量的值

使用命令set显示当前Shell中所有变量


使用命令env查看当前Shell中的系统全局变量

使用命令printenv 环境变量名称 查看环境变量。如果不加环境变量名称效果和env一样。

自定义变量

  • 基本语法

定义变量:变量名=变量值,注意:等号=前后不能有空格
撤销变量:unset 变量名
申明静态变量:readonly 变量,注意:不能unset

  • 变量定义规则

1.变量名可以由字母、数字和下划线组成,但不能以数字开头,环境变量名建议大写。
2.等号两侧不能有空格
3.在bash中,变量默认类型都是字符串类型,无法直接进行数值运算
4.变量的值如果有空格,需要使用双引号或者单引号括起来

  • 案例实操

1.定义变量A

2.给变量A重新赋值

3.撤销变量A

申明readonly变量B=2,不能被unset

在bash中,变量默认类型都是字符串类型,无法直接进行数值运算

变量的值如果有空格,需要使用双引号或单引号括起来

可以把局部变量提升为全局环境变量,可供其他Shell程序使用

在helloworld.sh文件中增加echo $B
将变量B提升为全局环境变量然后运行helloworld.sh文件

特殊变量

  • $n

基本语法
$n 功能描述,n为数字,$0代表该脚本的名称,$1-$9代表第一个到第九个参数,两位数以上的参数,需要用大括号括起来,比如 ${15}表示第十五个参数。

案例实操
使用命令vim helloworld.sh编辑脚本内容如下:

#!/bin/bash
echo "hello,wolrd"
echo $B
echo '#######$n的使用#######'
echo $0
echo $1
echo $2

执行脚本,查看结果

  • $#

基本语法
$# 可以获取输入参数的个数,擦汗给你用于循环,判断参数的个数是否正确以及加强脚本的健壮性。

案例实操

  • $*$@

基本语法
$* 这个变量代表命令行中所有的参数,它把所有变量看作一个整体
$@ 这个变量也是代表命令行中的所有的参数,不过它把每个参数分开对待。

案例实操

  • $?

基本语法
$? 是最后一次执行命令的返回状态。如果这个变量的值为0,证明上一个命令正确执行;如果这个变量的值为非0,则证明上一条命令执行出错。

案例实操

运算符

基本语法
使用命令$((运算式))或者$[运算式]

案例实操
计算(2+3)*4

条件判断

基本语法
使用命令test 条件 或者 [ 条件 ]
注意:1.中括号和条件之间一定要有空格!!!2.条件非空即为true ,比如[ itheima ]返回为true,[ ]返回为false

常用判断条件

  • 两个整数之间的比较
参数含义
-eq等于
-lt小于
-gt大于
-ue不等于
-le小于等于
-ge大于等于
  • 按照文件权限进行判断
参数含义
-r有读的权限
-w有写的权限
-x有执行的权限
  • 按照文件类型进行判断
参数含义
-e文件存在
-f文件存在并且是一个常规的文件
-d文件存在并且是一个目录

案例实操

  1. 23是否大于等于22

  2. helloworld.sh是否具有写权限

  3. /home/atguigu/目录是否存在

  4. 多条件判断(短路与和短路或,可以实现类似java中的三元表达式)

流程控制(重点)

if判断

基本语法

1.单分支

if [ 条件判断式 ];then
	程序
fi

或者

if [ 条件判断式 ]
then
	程序
fi

2.多分枝

if [ 条件判断式 ] 
then 
	程序
elif [ 条件判断式 ] 
then
	程序
else 
	程序
fi

案例实操
输入一个数字,如果是1,则输出:1! 5!;如果是2,则输出:L!T!C!;既不是1也不是2则输出:理塘猛虎!

if [ $1 -eq 1 ]
then
        echo -e "1!\t5!"
elif [ $1 -eq 2 ]
then
        echo -e "L!T!C!"
else
        echo "理塘最强猛虎"
fi

case语句

基本语法

case $变量名 in
"值1")
	如果变量的值等于值1,执行该部分
;;
"值2")
	如果变量的值等于值2,执行该部分
;;
*)
	如果变量的值都不是以上的值,则执行此部分
;;
esac

注意事项:
1.case行尾必须为单词in,每一个模式匹配必须以右括号)结束。
2.双分号::表示命令序列化结束,相当于java中的break
3.最后的*)表示默认情况,相当于java中的default

案例实操
输入一个数字,如果是1,则输出:1! 5!;如果是2,则输出:L!T!C!;既不是1也不是2则输出:理塘最强猛虎!

for循环

基本语法1

for (( 初始值;循环控制条件;变量变化 ))
do 
	程序
done

案例实操
从1加到100

sum=0
for ((i=1;i<=100;i++))
do
        sum=$[$sum+$i]
done
echo $sum


基本语法2

for 变量 in 值1 值2 值3...
do
	程序
done

案例实操
打印所有输入的参数

for i in $1 $2 $3
do
        echo $i
done


比较$*$@的区别

当它们(指$*$@)不被双引号包括时:
两者没有区别。

当它们(指$*$@)被双引号包括时:
$* 会将所有的参数作为一个整体,如果使用for循环来循环参数,只会执行一次。
$@会将每个参数当成是独立的个体,如果使用for循环,那么循环的次数会等于参数个数。

while循环

基本语法

while [ 条件判断式 ]
do
	程序
done

案例实操
从1加到100

i=1
sum=0
while [ $i -le 100 ]
do
        sum=$[$sum+$i];i=$[$i+1]
done
echo $sum

read读取控制台输入(附$()命令替换 )

基本语法
read (选项) (参数)

选项说明

选项功能
-p指定读取值时的提示符
-t指定读取值时等待的时间(秒),如果-t不加则一直等待

参数说明
指定读取值的变量名

案例实操
提示7秒内,读取控制台输入的名字

#!/bin/bash
read -t 7 -p "请输入你的姓名:" username
echo $username 

  • $()命令替换
echo $(echo 123)

函数

系统函数

  • basename

基本语法
basename [string/pathname] [suffix] 功能:basename命令会删掉所有的前缀包括最后一个"/"字符,然后将字符串显示出来
可以理解为取路径里的文件名称。

选项说明
suffix为后缀,如果suffix被指定了,basename会将pathname或者string中的suffix去掉。

案例实操
截取/root/helloworld.sh路径中的文件名称

basename /root/read_test.sh

截取/root/helloworld.sh路径中的文件名称,同时截去文件类型

basename /root/read_test.sh .sh

  • dirname

基本语法
使用命令dirname 文件绝对路径 从欸顶的包含绝对路径的文件名中除去文件名,然后返回剩下的路径
dirname 可以理解成取文件路径的绝对路径名称。

案例实操
获取helloworld.sh文件的路径

自定义函数

基本语法

[function] funname[()]
{
	Action;
	[return int;]
}

经验技巧

  1. 必须在调用函数之前,先声明函数,shell脚本是逐行运行。不会像其他语言那么先编译后运行。
  2. 函数返回值,只能通过$?系统变量获得,如果有return返回,则以return作为返回值,返回值必须为0~255中的一个数字。如果没有return,则以最后一条命令运行结果作为返回值。

案例实操
计算两个输入参数的值。

#!/bin/bash
function sum()
{
s=0
s=$[$1+$2]
echo "$s"
}
read -p "Please input the number1: " n1;
read -p "Please input the number2: " n2;
sum $n1 $n2;

正则表达式匹配

正则表达式使用单个字符串,匹配一系列符合某个语法规则的字符串。在很多文本编辑器里。正则表达式通常被用来检索,替换那些符合某个模式的文本。在Linux中,grep、sed、awk等文本处理工具都支持通过正则表达式进行模式匹配。

  • 常规匹配

一串不包含特殊字符的正则表达式匹配它自己。例如
使用命令cat /etc/passwd | grep root 会匹配所有包含root的行

  • 常用特殊字符
特殊字符功能及例子
^匹配一行的开头,比如grep ^a会匹配所有a开头的行
$匹配一行的结束,例如grep a$会匹配所有a结束的行
.匹配一个任意的字符,例如grep r..t 可以匹配root,rbbt,ract等等
*星号不单独使用,他表示匹配一个字符串0次或多次,grep .*表示一切
[ ]中括号表示匹配某个范围的一个字符,比如[1-5]表示匹配1到5中的一个数字
\表示转义,比如有时我们想匹配星号,美元符号之类的可以使用\* 或者\$
{n}配合其他特殊字符使用,n表达字符的个数,使用grep需要添加参数-E

注意:正则表达式是按匹配!!!

案例实操

文本处理工具

cut

cut的功能就是在文件中负责剪切数据用。cut命令从文件的每一行剪切字节、字符和字段并将这些字节、字符和字段输出。

  • 基本用法

cut [选项参数] filename
说明:默认分隔符是制表符(tab键)

  • 选项参数说明
选项参数功能
-f列号,提取第几列
-d分隔符,按照指定分隔符分割列,默认是制表符(tab)
-c按字符进行切割 后面加n表示取第几列 比如-c 1
  • 案例实操

数据准备
使用vim编辑器在名为cut.txt的文件中添加如下内容

wen zhe
zhou jiang
wo wo
lai lai
le le

切割cut.txt第一列
使用命令cut -f 1 -d " " cut.txt

切割cut.txt第二列,第三列
使用命令cut -f 2,3 -d " " cut.txt

在cut.txt文件中切割出zhou
使用命令cat cut.txt | grep zhou | cut -f 1 -d " "

选取系统PATH变量值,第2个":"开始后的路径
使用命令echo $PATH | cut -d ":" -f 3

awk

awk是一款强大的文本分析工具,把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行分析处理。

  • 基本用法

使用命令 awk [选项参数] '/pattern1/{action1} /pattern2/{action2}... ' filename
pattern:表示awk在数据中查找的内容,就是匹配模式(正则表达式)
action:在找到匹配内容时所执行的一系列命令

  • 选项参数说明
选项参数功能
-F指定输入文件分隔符
-v赋值一个用户定义变量
  • 案例实操

1.数据准备
使用命令cp /etc/passwd ./passwd

2.搜索passwd文件以root关键字开头的所有行,并输出该行的第7列。
使用命令awk -F ":" '/^root/{print $7}' passwd

3.搜索passwd文件以root关键字开头的所有行,并输出该行的第1列和第7列,中间以","号分割。
使用命令awk -F ":" '/^root/{print $1","$7}' passwd

注意!只有匹配了pattern的行才会执行action
4.只显示/etc/passwd的第1列和第7列,以逗号分隔,且在所有行前面添加列名user,shell在最后一行添加"dahaige,/bin/zuishuai"。
使用命令awk -F ":" 'BEGIN{print "user,shell"} {print $1","$7} END{print "dahaige,/bin/zuishuai"}' passwd

注意!BEGIN 在所在数据读取行之前执行END在所在数据执行之后执行
5.将passwd文件中的用户id增加数值1并输出

  • awk的内置变量
变量说明
FILENAME文件名
NR已读的记录数(当前行号)
NF浏览记录的域的个数

(1)统计 passwd 文件名,每行的行号,每行的列数

[atguigu@hadoop101 shells]$ awk -F : '{print "filename:" FILENAME ",linenum:"NR ",col:"NF}' passwd
filename:passwd,linenum:1,col:7
filename:passwd,linenum:2,col:7
filename:passwd,linenum:3,col:7

(2)查询 ifconfig 命令输出结果中的空行所在的行号

[atguigu@hadoop101 shells]$ ifconfig | awk '/^$/{print NR}'
9
18
26

(3)切割 IP

[atguigu@hadoop101 shells]$ ifconfig ens33 | awk '/netmask/ {print $2}'
192.168.6.101
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值