当前位置: 首页 > news >正文

Liunx高级程序设计-Shell

引入

完成以下任务 :
判断用户家目录下( ~ )下面有没有一个叫 test 的文件夹
如果没有,提示按 y 创建并进入此文件夹,按 n 退出
如果有,直接进入,提示请输入一个字符串,并按此字符串创建一个文件,如果此
文件已存在,提示重新输入,重复三次自动退出,不存在创建完毕,退出
简单的进行命令堆积无法完成以上任务,这就需要学习相应的 shell 脚本语法规则了
简介
Shell 的概念
是一种应用程序 , 也是一种设计语言
作为应用程序
系统分为 , 硬件层 ,Liunx 系统层 ,Shell, 应用程序层 , 如图 1
此时 Shell 的作用是沟通应用程序层与 Liunx 系统层 , Shell 解析器
Shell 解析器常用的有三种 , 分别是 sh,ash,bash, 一般情况下使用 bash
可以使用 echo $SHELL 查看使用的那种解析器 , 如图 2
作为设计语言
概念 :shell 脚本语言 , 不需要编译 , 直接解析执行 ( 批处理 )
优点 : 简化我们对系统的管理与应用程序的部署过程
名词 :
批处理 : 大量的循环的数据处理 , 如扫描当前根目录下是否存在 a.txt, 此时需要在
当前根目录所有文件夹中一一寻找
脚本语言 : 我们只需使用任意文本编辑器,按照语法编写相应程序 , 增加可执行权
, 即可在安装 shell 命令解释器的环境下执行的代码语言 , python,html,css
Shell 脚本的分类
系统调用
这类脚本无需用户调用,系统会在合适的时候调用,如: /etc/profile
~/.bashrc
/etc/profile:
此文件为系统的每个用户设置环境信息 , 当用户第一次登录时 , 该文件被执行 ,
系统的公共环境变量在这里设置
开机自启动的程序,一般也在这里设置
注意 : 如果在该文件中配置 , 需要从新登录用户才可生效
~/.bashrc
用户自己的家目录中的 .bashrc
登录时会自动调用,打开任意终端时也会自动调用
这个文件一般设置与个人用户有关的环境变量,如交叉编译器的路径等等
/etc/profile ~/.bashrc 的关系 , 如下图
用户编写
需要手动调用
注意 : 无论是系统调用的还是需要我们自己调用的,其语法规则都一样

第一个Shell脚本

1, 创建 Hello.sh 文件
2, 编写以下代码
#!/bin/bash
echo "Hello Shall"
3, 执行 hello.sh 文件
./Hello.sh
说明:
#! 用来声明脚本由什么 shell 解释,否则使用默认 shell
# 表示注释本行
注意:
创建文件时 :
如果是在 windows 中创建编写的 Shell 脚本文件 , 拖拽到 Liunx 下无法运行 , 因为
Windows Liunx \ 表示的含义不同 , 所以导致程序无法被识别
解决方案 1:
Liunx 中使用 vim 编辑器 , 在最后一行模式输入 set ff=unix
解决方案 2:
Linux 中安装 dos2unix, 使用 dos2unix 转换
步骤 :
1, 命令行输入 :sudo apt-age install dos2unix
2, 命令行输入 :dos2unix 文件地址
编写代码 :
# 注释
#! 用来声明脚本由什么 shell 解释,否则使用默认 shell
echo 输出
执行脚本方式 :
方式 1: 使用 sh bash
sh 文件路径
bash 文件路径
方式 2:./ 文件路径
需要可执行权限 , 添加权限命令 :chmod +x 文件路径
+ 增加权限
- 减少权限
x: 可执行
以上方式会开启子 Shell
:
chmod +x hishell.sh
方式 3:source 文件名或 . 文件名
source 文件路径 借鉴 cshell
. 文件路径 借鉴 bash
以上方式不会开启子 Shell
开启子 Shell 与不开启的区别
开启子 Shell , Shell 中的变量父 Shell 不可见
区别 :
./ bash 执行过程基本一致,
bash 明确指定 bash 解释器去执行脚本,脚本中 #! 指定的解释器不起作用
./ 前者首先检测 #! ,使用 #! 指定的 shell ,如果没有使用默认的 shell
./ bash 去执行会在后台启动一个新的 shell 去执行脚本
. 去执行脚本不会启动新的 shell, 直接由当前的 shell 去解释执行脚本

变量

分类

按是否为系统提供分类
系统变量
自定义变量
按作用范围分类
全局变量 : 当前 Shell 中的所有 Shell 都可使用 ( 自己与其中的子 Shell)
局部变量 : 当前 Shell 中使用 ( 自己使用 )
系统预定义变量
常用系统变量
:HOME,PWD,SHELL,USER
查看系统变量的值
语法 :
echo 变量名
:
echo $HOME
显示系统中的全局变量
语法 :
env printenv
:
env
printenv
显示当前 Shell 中的所有变量
语法 :
set
:
set

自定义变量

基本语法
定义变量 :
变量名 = 变量值 ;
注意 :
= 号前后不能有空格
声明的变量为局部变量
撤销变量
unset 变量名
声明只读变量
语法 :
readonly 变量
注意 :
只读变量不能撤销 , 不能修改值
示例 :
#!/bin/bash
readonly num=10
#unset num
num=100
echo $num
引用变量
$ 变量名
注意 : 如果变量不存在返回空
导出变量
作用 :
将当前变量导入到系统变量中
语法 :
export 变量名
注意 :
只在当前终端有效
需要使用 source . 执行
示例 :
代码
export DATA=1000
运行
source 文件路径
查看变量
env
declare -i: 将变量强制转换为数字
#!/bin/bash
# 注意 : 必须使用 ./ 运行
declare -i DATA=1
DATA=$DATA+1
echo $DATA
定义规则
1, 变量名由字母 , 数字 , 下划线组成 , 能不能使用数字开头 , 环境变量名不建议大写
2,= 号两侧不能有空格
3, bash , 变量默认类型为都是字符 , 无法直接进行数值运算
4, 变量值如果有空格 , 需要使用双引号或单引号包裹
注意 :"" '' 的区别
"" 会解析变量值
'' 不会解析变量值
示例 :
#!/bin/bash
num=1000
echo "num=$num"
echo 'num=$num'

预设变量

$# :传给 shell 脚本参数的数量
$* :传给 shell 脚本参数的内容
$1 $2 $3 ... $9 :运行脚本时传递给其的参数,用空格隔开
$? :命令执行后返回的状态
"$?" 用于检查上一个命令执行是否正确 ( Linux 中,命令退出状态为 0 表示该命令
正确执行,任何非 0 值表示命
令出错 )
$0 :当前执行的进程名
$$ :当前进程的进程号
"$$" 变量最常见的用途是用作临时文件的名字以保证临时文件不会重复
示例
#!/bin/bash
# 执行命令sh ./07_code.sh a b c
echo "参数个数:$#"
echo "参数内容:$*"
echo "第一个参数:$1"
echo "第二个参数:$2"
echo "第三个参数:$3"
#ps是用来查看系统进程的命令 -A
#常用参数
#-A 显示所有进程(同-e)
#-a 显示当前终端的所有进程
#-u 显示进程的用户信息
#-o 以用户自定义形式显示进程信息
#-f 显示程序间的关系
ps -A | grep bash
echo "指令结果:$?"
echo "进程名称:$0"
echo "进程号:$$"

脚本变量的特殊用法

"": 包含的变量会被解释
'': 包含的变量会作为字符串处理
``: 反引号中的内容作为系统命令,并执行其内容,可以替换输出为一个变量
\: c 语言 \n \t \r \a echo 命令需加 -e 转义 (bash 解析器需求 )
( 命令 ): 由子 shell 来完成 , 不影响当前 shell 中的变量 , 命令前后必须有空格
{ 命令 }: 在当前 shell 中执行 , 会影响当前变量 , 命令前后必须有空格
示例
#!/bin/bash
num=100;
echo "num=$num"
echo 'num=$num'
echo "当前时间:`date`"
echo '当前时间:`date`'
echo -e "abc\n123"
echo -e "##\n##"
(
num=1000
echo "()内打印num变量:$num"
)
echo "()外打印num变量:$num"
{
num=1
echo "{}内打印num变量:$num"
}
echo "{}外打印num变量:$num"

键盘录入

输入

read 变量名
read -p 提示内容 变量名
#!/bin/bash
num=0
# echo "请输入一个数:"
# read num
# 或
read -p "请输入一个数:" num
echo "num=$num"

条件测试语句

语法

语法 1:test 条件
语法 2:[ 条件 ]、
注意 : 条件前后必须有空格

文件测试

文件测试:测试文件状态的条件表达式
-e 是否存在
-d 是否为目录
-f 是否为文件
-r 是否可读
-w 是否可写
-x 是否可执行
-L 是否连接
-c 是否字符设备
-b 是否块设备
-s 文件非空
#!/bin/bash
read -p "请输入文件名:" fileName
#-e:测试文件是否存在
test -e $fileName
echo "是否存在:$?"
#-f是否为文件
test -f $fileName
echo "是文件吗:$?"
#-d是否为文件夹
test -d $fileName
echo "是文件夹吗:$?"
#-r是否可读
[ -r $fileName ]
echo "是否可读:$?"
#-w是否可读
[ -w $fileName ]
echo "是否可写:$?"
#-x是否可执行
[ -x $fileName ]
echo "是否可执行:$?"

字符串测试

= 两个字符串相等
!= 两个字符串不相等
-z 空串
-n 非空串
注意 := != 前后要有空格
#!/bin/bash
str01="hello"
str02="world"
str03="hello"
[ $str01 = $str02 ]
echo "str01等于str02:$?"
[ $str01 = $str03 ]
echo "str01等于str03:$?"
test $str01 != $str02
echo "str01不等于str02:$?"
test $str01 != $str03
echo "str01不等于str03:$?"
[ -z $str01 ]
echo "str01是否是空串:$?"
[ -n $str01 ]
echo "str01是否不是空串:$?"

数值测试

-eq 数值相等
-ne 数值不相等
-gt 1 大于数 2
-ge 1 大于等于数 2
-le 1 小于等于数 2
-lt 1 小于数 2
#!/bin/bash
num01=10
num02=3
# -eq 数值相等
test $num01 -eq $num02
echo "num01等于num02:$?"
# -ne 数值不相等
test $num01 -ne $num02
echo "num01不等于num02:$?"
# -gt 数 1 大于数 2
test $num01 -gt $num02
echo "num01大于num02:$?"
# -ge 数 1 大于等于数 2
[ $num01 -ge $num02 ]
echo "num01大于等于num02:$?"
# -le 数 1 小于等于数 2
[ $num01 -le $num02 ]
echo "num01小于等于num02:$?"
# -lt 数 1 小于数 2
[ $num01 -lt $num02 ]
echo "num01小于num02:$?"

扩展

#${num:-val} 如果num存在,返回num,否则返回val
echo ${x:-10}
#${num:=val} 如果num存在,返回num,否则返回val,并将val赋值给num
echo ${y:=10}
echo $y

复合测试

&&
command1 && command2
&& 左边命令( command1 )执行成功 ( 即返回 0 shell 才执行 && 右边的命令
command2
||
command1 || command2
|| 左边的命令( command1 )未执行成功 ( 即返回非 0 shell 才执行 || 右边的命令
command2
#!/bin/bash
#输入一个数判断是否在0~100之间
read -p "请输入一个数" num
test $num -gt 0 && test $num -lt 100
echo "$num 是否在0~100之间:$?"

多重条件

-a:
-o:
!:
#!/bin/bash
#输入文件名称,判断文件是否可读可写可执行
read -p "请输入文件名称" fileName
test -r $fileName -a -w $fileName -a -x $fileName
echo "文件可读可写可执行:$?"
test -r $fileName -o -w $fileName
echo "文件可读或可写:$?"
test ! -x $fileName
echo "文件是否不可执行:$?"

控制语句

if语句

if[条件一];then

        执行第一段程序

else
        执行第二段程序

fi

num01=10
num02=16
#获取两数最大值
if [ $num01 -gt $num02 ];then
echo $num01
else
echo $num02
fi
if [ 条件1 ];then
执行第1段程序
elif [ 条件2 ];then
执行第2段程序
elif [ 条件3 ];then
执行第3段程序
...
else
执行第n段程序
fi
#!/bin/bash
read -p "请输入考试成绩" score
if [ $score -lt 0 -o $score -gt 100 ];then
echo "成绩不应小于0,或大于100"
elif [ $score -lt 60 ];then
echo "D"
elif [ $score -lt 70 ];then
echo "C"
elif [ $score -lt 85 ];then
echo "B"
else
echo "A"
fi
#!/bin/bash
#键盘输入一个文件名,判断是否存在改文件,
#如果存在显示文件内容
#如果不存在 创建该文件,并输入内容且输出文件内容。
read -p "请输入文件名称" fileName
#-e:是否存在
if [ -e $fileName ];then
#-d:是否为文件夹
#-o:或
#-s:是否为空文件
if [ -d $fileName -o -s $fileName ];then
echo "是文件夹或空文件"
else
cat $fileName
fi
else
#touch 创建文件
touch $fileName
read -p "请输入内容" info
#echo 输出的内容 >> 输出的地方,默认为控制台
echo $info >> $fileName
#cat 读取文件内容
cat $fileName
fi

case语句

语法:
case $ 变量名 in
" 1")
语句 1
;;
" 2")
语句 2
;;
*)
语句 3
;;
esac
扩展 :
exit 1 # 退出 shell
#!/bin/bash
read -p "是否继续" tag
case $tag in
"yes" | "YES")
#y* 以小写y开头
echo "继续"
;;
"no" | "NO")
echo "退出"
;;
*)
echo "输入有误"
;;
esac
#!/bin/bash
read -p "是否继续" tag
case $tag in
y* | Y*)
#y* 以小写y开头
echo "继续"
;;
n* | N*)
echo "退出"
;;
*)
echo "输入有误"
;;
esac

for语句

语法:
for (( 初始值 ; 限制值 ; 执行步阶 ))
do
程序段
done
#!/bin/bash
#计算100以内数之和
#declare -i s强制将s作为int型数值,需要使用./运行
declare -i s=0
declare -i sum=0
for (( s=0; s<=100; s++ ))
do
sum=$sum+$s;
done
echo $sum

语法2:

for var in con1 con2 con3 ...
do
程序段
done
#!/bin/bash
str01="A"
str02="B"
str03="C"
for v in $str01 $str02 $str03
do
echo $v
done
#!/bin/bash
#遍历文件夹
for fileName in `ls`
do
if [ -d $fileName ];then
echo "$fileName 是文件夹"
elif [ -f $fileName ];then
echo "$fileName 是文件"
fi
done

while语句

语法:
while [ 条件 ]
do
程序段
done
#!/bin/bash
declare -i i=0
declare -i sum=0
while [ $i -le 100 ]
do
sum=$sum+$i
i=$i+1
done
echo $sum

扩展:

变量名 =$(( 1 + 2 ))
变量名 =$(( 1 - 2 ))
变量名 =$(( 1 * 2 ))
变量名 =$(( 1 / 2 ))
变量名 =$(( 1 % 2 ))
变量名 =$(( 变量名 -- ))
变量名 =$(( -- 变量名 ))
变量名 =$(( 变量名 ++ ))
变量名 =$(( ++ 变量名 ))
变量名 =$(( -10 > 1 ? 10 : 1 ))

until语句

语法
until [ condition ]
do
程序段
done
这种方式与 while 恰恰相反,当 condition 成立的时候退出循环,否则继续循环。
#!/bin/bash
declare -i i=100
declare -i sum=0
#lt小于
until [ $i -lt 0 ]
do
sum=$sum+$i;
i=$i-1
done
echo $sum

函数

语法:

1, 定义
2, 调用
定义:
语法 1
函数名 (){
程序段
}
语法 2
function 函数名 (){
程序段
}
调用:
语法
函数名 参数 1 参数 2
#!/bin/bash
#函数定义
add(){
declare -i num=0
num=$1+$2
return $num
}
#函数调用
add 10 2
#获取结果输出
echo "返回值为:$?"

注意:
 

当函数定义与函数调用不在一个文件中需要在函数调用所在的文件中使用 source 引用函
数定义的文件
#myfun.sh定义函数
#!/bin/bash
function add(){
declare -i num=0
num=$1+$2
return $num
}
#24_code.sh调用函数
#!/bin/bash
#导入函数所在的文件
source myfun.sh
add 1 2
echo $?

相关文章:

  • React实现登录授权功能
  • 专业爬虫框架 -- scrapy初识及基本应用
  • 精通Git(第2版)读书笔记
  • Linux(CentOS7.5):通过docker安装redis
  • Golang WebSocket 心跳
  • WPF 简单绘制矩形
  • 10、SQL注入——数据库基础
  • 【2023.12.4练习】数据库知识点复习测试
  • dp-矩阵连乘
  • 前后端参数传递总结
  • 毕业项目分享
  • 纯C读取文件实现解析H264裸流每一帧数据
  • 系列十三、SpringBoot的自动配置原理分析
  • 【工具使用-Audition】如何使用Audition频谱分析
  • 鸿蒙(HarmonyOS)应用开发——管理组件状态
  • 《Javascript数据结构和算法》笔记-「字典和散列表」
  • Apache Zeppelin在Apache Trafodion上的可视化
  • css系列之关于字体的事
  • ES6之路之模块详解
  • Flex布局到底解决了什么问题
  • Git 使用集
  • iOS编译提示和导航提示
  • iOS仿今日头条、壁纸应用、筛选分类、三方微博、颜色填充等源码
  • JS进阶 - JS 、JS-Web-API与DOM、BOM
  • Redis提升并发能力 | 从0开始构建SpringCloud微服务(2)
  • Redis学习笔记 - pipline(流水线、管道)
  • SAP云平台运行环境Cloud Foundry和Neo的区别
  • SpingCloudBus整合RabbitMQ
  • 关键词挖掘技术哪家强(一)基于node.js技术开发一个关键字查询工具
  • 快速体验 Sentinel 集群限流功能,只需简单几步
  • 融云开发漫谈:你是否了解Go语言并发编程的第一要义?
  • 思考 CSS 架构
  • 微信如何实现自动跳转到用其他浏览器打开指定页面下载APP
  • 消息队列系列二(IOT中消息队列的应用)
  • 如何在招聘中考核.NET架构师
  • ​ubuntu下安装kvm虚拟机
  • (超简单)构建高可用网络应用:使用Nginx进行负载均衡与健康检查
  • (第27天)Oracle 数据泵转换分区表
  • (附源码)ssm高校运动会管理系统 毕业设计 020419
  • (一)ClickHouse 中的 `MaterializedMySQL` 数据库引擎的使用方法、设置、特性和限制。
  • (一)基于IDEA的JAVA基础10
  • (转)Linux整合apache和tomcat构建Web服务器
  • (转)socket Aio demo
  • (转)机器学习的数学基础(1)--Dirichlet分布
  • (转载)Google Chrome调试JS
  • (状压dp)uva 10817 Headmaster's Headache
  • .NET Core Web APi类库如何内嵌运行?
  • .NET 命令行参数包含应用程序路径吗?
  • .NET 使用配置文件
  • @Autowired注解的实现原理
  • @Transactional注解下,循环取序列的值,但得到的值都相同的问题
  • [14]内置对象
  • [Android]使用Android打包Unity工程
  • [Android]一个简单使用Handler做Timer的例子
  • [bzoj1901]: Zju2112 Dynamic Rankings