Shell编程从入门到实践——实践篇

news2024/11/9 5:45:29

欢迎关注 「Android茶话会」

  1. 「学习之路」 取Android技术路线经典电子书
  2. 「pdf」 取阿里&字节经典面试题、Android、算法、Java等系列武功秘籍。
  3. 「天涯」 取天涯论坛200+精彩博文,包括小说、玄学等

背景

之前在搞一些CI/CD,使用到了shell脚本,shell的开箱即用确实比较方便,至少无需在宿主上安装运行环境,本篇文章主要解释shell脚本实践过程中一些经验总结。

实践篇

模块化

刚开始看一些之前的shell脚本,一个脚本大几百行,很少有函数的情况,其实shell脚本也可以函数化,按照模块的拆分,这样就会带来良好的可读性和可维护性,通常我们会先定义main函数,将功能分解为一个个子函数

  • 模块化之前
    模块化之前
  • 模块化之后
    模块化之后
#!/bin/bash

localvar="fun1"

main() {
    func1
    func2
}

func1() {
    local localvar="funlocal"
    echo ${localvar}
    localvar="fun2"
}

func2() {
    echo ${localvar}
}

main "$@"

函数

函数是模块化的基础,一个函数往往负责一件事件

  • 函数名后面的圆括号不加任何参数
  • 函数的完整定义必须置于函数的调用之前
函数名 (){
	函数体
}

传参

#!/bin/bash

print_something(){
    echo "hello $1" # $1 获取第一个参数
}
print_something Lion # Lion 为参数
print_something Frank # Frank 为参数
$1~$9:函数的第一个到第9个的参数。
$0:函数所在的脚本名。
$#:函数的参数总数。
$@:函数的全部参数,参数之间使用空格分隔。
$*:函数的全部参数,参数之间使用变量$IFS值的第一个字符分隔,默认为空格,但是可以自定义。
$?:显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。可以用于函数返回值

返回值

testFun(){
    echo "helloworld!"
    return 99
}

# 千万要注意shell并不像其他语言直接返回返回值,其返回值放到$?中,这也是为什么只能返回整型的原因
# 所以这种承接方法是错误的,获取到的值是echo打印的内容
# return_value=`testFun`
# 以下才是正确获取通过return返回的返回值的正确写法
testFun
echo "the return value is: $?"

局部变量

  • 不做特殊声明,shell中变量都是全局变量
  • 局部变量 使用 local 关键字,函数内外同时存在同名变量,则函数内部会覆盖函数外部变量

脚本之间引用

模块化之后多个脚本和公共参数之间是可以相互复用的 这时候可以通过 souce或者点号来调用所需要的脚本

source ./util.sh
. ./util.sh

错误处理

如果什么都不做,在shell中命令出错也不影响,默认会继续执行,这会带来麻烦,有时候我们需要区分业务错误和系统错误,比如在脚本执行遇到系统错误之后就应该退出,遇到业务错误,需要根据业务错误来确定是否往下执行,有以下几种方式来控制shell的错误

set 命令

  • set -e

只要脚本发生错误就终止执行,set +e表示关闭-e选项,set -e表示重新打开-e选项,但是要注意这个命令不适与管道操作

set +e
command1
command2
set -e

管道处理需要借助

  • set -o pipeline

通常我们会把这些命令放在一起使用

# 写法一
set -Eeuxo pipefail

# 写法二
set -Eeux
set -o pipefail

短路符号

如果command正常退出,返回0,|| 运算符右半部分被短路,脚本继续执行。
如果command异常退出,返回非0, 运算符右半部分执行,脚本exit 1。

command || exit 1

# 写法一
command || { echo "command failed"; exit 1; }

# 写法二
if ! command; then echo "command failed"; exit 1; fi

# 写法三
command
if [ "$?" -ne 0 ]; then echo "command failed"; exit 1; fi

使用trap 捕获信号量

用来在bash脚本中响应系统信号,trap命令必须放在脚本的开头。否则,它上方的任何命令导致脚本退出,都不会被它捕获。标准格式

$ trap [动作] [信号1] [信号2] ...

HUP:编号1,脚本与所在的终端脱离联系。
INT:编号2,用户按下 Ctrl + C,意图让脚本终止运行。
QUIT:编号3,用户按下 Ctrl + 斜杠,意图退出脚本。
KILL:编号9,该信号用于杀死进程。
TERM:编号15,这是kill命令发出的默认信号。
EXIT:编号0,这不是系统信号,而是 Bash 脚本特有的信号,不管什么情况,只要退出脚本就会产生。

$ trap 'rm -f "$TMPFILE"' EXIT

表示 脚本遇到EXIT信号时,就会执行rm -f “$TMPFILE”

调试

也没有特别好的办法,可以让不同级别的日志打印出不同的颜色

function debug()
{
    echo -e "\033[37m$1\033[0m"
}
function infolog()
{
    echo -e "\033[32m$1\033[0m"
}
function warn()
{
    echo -e "\033[33m$1\033[0m"
}
function error()
{
    echo -e "\033[31m$1\033[0m"
}

其他细节

预定义默认值

  • ${varname:-word} varname存在且不为空,则返回它的值,否则返回word
  • ${varname:=word} varname存在且不为空,则返回它的值,否则将它设置为word并返回word
  • ${varname:+word} varname存在且不为空,在返回word,否则返回空值,它的目的是测试变量是否存在
  • ${varname:?message} 如果变量varname存在且不为空,则返回它的值,否则打印出varname: message,并中断脚本的执行,它的目的是防止变量未定义

( ) 与 ()与 (){}的区别

前者用于命令执行,返回命令返回值

all_files=`ls` # 获取ls命令的执行结果
all_files=$(ls) # 效果同上

后者用于变量展开

echo ${A}B

[]和[[ ]] 、(())

在使用[]或者test指令进行字符串判空时,需要在引用的变量上加上双引号""。
如果使用[[]]的话就不需要。
$(())用来做整数运算的

curl中携带参数

curl中需要用单引号,数字和字符还不一样,注意tesMsg

jobId="78707463"
tesMsg="msg:需要找专人审批"

curl -X POST https://xxxx/openapi/xxxx/job/update_msg -H "Content-Type: application/json" -d '{
"jobId":'$jobId',
"jobMsg":"'"${tesMsg}"'"
}'
  1. 「学习之路」 取Android技术路线经典电子书
  2. 「pdf」 取阿里&字节经典面试题、Android、算法、Java等系列武功秘籍。
  3. 「天涯」 取天涯论坛200+精彩博文,包括小说、玄学等

您的 点赞、评论、转发 是对我的巨大鼓励!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/677772.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

nvdiffrec在Windows上的配置及使用

nvdiffrec是NVIDIA研究院开源的项目,源代码地址:https://github.com/NVlabs/nvdiffrec ,论文为《Extracting Triangular 3D Models, Materials, and Lighting From Images》,从图像中提取三角形三维(三角网格)模型、空间变化的材质…

uni-app微信小程序获取手机号授权登录(复制即用,js完成敏感数据对称解密,无需走服务端处理)

目录 一、示例 二、具体实现说明 一、示例 获取到的手机号 二、具体实现说明 属性说明 属性名说明生效时机getphonenumber获取用户手机号回调open-type"getPhoneNumber" 按钮写法 <template><view class"login"><view class"content…

为什么要写这个带点玄幻气息的英语单词记忆博客

&#x1f31f;博主&#xff1a;命运之光 ☀️专栏&#xff1a;英之剑法&#x1f5e1; ❤️‍&#x1f525;专栏&#xff1a;英之试炼&#x1f525; ☀️博主的其他文章&#xff1a;点击进入博主的主页 &#x1f433; 开篇想说的话&#xff1a;开学就大三了&#xff0c;命运之光…

DMA详解及应用(嵌入式学习)

DMA 0. 前言1. DMA作用2. DMA特性3. DMA寄存器4. DMA的增量或者循环模式5. 练习 0. 前言 DMA&#xff08;Direct Memory Access&#xff0c;直接内存访问&#xff09;是一种计算机系统中用于高效地实现数据传输的技术。它允许数据在外设和内存之间直接传输&#xff0c;而无需C…

GEE:为每个对象(斑块/超像素)添加属性

作者:CSDN @ _养乐多_ 本文将介绍为每个对象(斑块/超像素)添加属性的代码。并举例将最近距离作为属性添加到每个对象(斑块/超像素)特征中。 结果如下图所示, 文章目录 一、代码二、代码链接一、代码 这段代码的目的是对动态世界土地覆盖图像进行分析,并提取出其中的目…

贪婪算法简介-数据结构和算法教程

贪婪算法是一种算法范例&#xff0c;它遵循在每个阶段进行局部最优选择的问题求解启发式&#xff0c;希望找到全局最优值。换句话说&#xff0c;贪婪算法在每一步都选择最好的可能选项&#xff0c;而不考虑该选择对未来步骤的影响。 当一个问题可以被划分成更小的子问题&#…

1.GPIO的工作原理

1.stm32引脚说明&#xff1a; 对于stm32f103zet6&#xff1a; 一共有7组io口&#xff1b;每组io口有16个io&#xff1b;一共有16*7112个io&#xff1b;分组情况为&#xff1a;GPIOA&#xff0c;GPIOB~GPIOG&#xff1b; 2.GPIO的基本结构&#xff1a; 3.GPIO的工作模式&…

C++入门:类和对象(后)

目录 前言&#xff1a; 一&#xff1a;static成员 (1)概念 (2)特性 (3)例子 二&#xff1a;explicit关键字 三&#xff1a;内部类 (1)概念 (2)特性 (3)实例 四&#xff1a;匿名对象 (1)概念 (2)特性 (3)实例 五&#xff1a;拷贝对象时的一些编译器优化 (1)引入 …

Spring整合MyBatis底层原理

Spring整合MyBatis底层原理 项目结构图 项目代码 build.gradle需要进入的依赖 // testImplementation(platform("org.junit:junit-bom:5.9.1")) // testImplementation("org.junit.jupiter:junit-jupiter")implementation("org.aspectj:aspect…

电池SOC和动力电池OCV功率联合估计研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

爱心方程(理科生的浪漫?)

目录 前言 C/C 源代码 扩展 Java Python HTML 前言 这个在大一的时候就想找了&#xff0c;然后后面是找到了一个&#xff0c;但是忘记出处了。我决定把可以找到的所有爱心给整理一下&#xff0c;为了实现“理科生的浪漫”&#xff01;&#xff01;&#xff01; C/C 首先…

你认为年轻人存款难吗?难啊难,难如上青天!!!

近日&#xff0c;有调查称“大概五分之一的年轻人存款在一万元以内。10万元存款是一个“坎”&#xff0c;存款超过10万就会超过53.7%的人。”“年轻人”“存款”两个词碰撞在一起&#xff0c;引来了广泛的关注和讨论。你认为年轻人存款难吗&#xff1f;可以从以下几个角度发表你…

Linux Nacos 设置systemctl service 并添加为开机启动

为方便在启动服务器时&#xff0c;不需要一个一个手动启动服务&#xff0c;需要把nacos设置为开机启动。方法如下&#xff1a; 在/usr/lib/systemd/system 目录下面添加nacos.service脚本&#xff1a; # 下面这一行必须有&#xff0c;不然会报错 #vim /usr/lib/systemd/system…

libevent(3)IO模型基础知识

一、用户态和内核态 我们知道现在的操作系统是分层的&#xff0c;内核封装了与底层的接口&#xff0c;通过系统调用提供给上层应用使用。 当进程运行在内核空间时&#xff0c;它就处于内核态&#xff1b;当进程运行在用户空间时&#xff0c;它就处于用户态。 当我们需要进行IO操…

【小沐学Python】网络爬虫之requests

文章目录 1、简介2、requests方法2.1 get2.2 post 3、requests响应信息4、requests的get方法4.1 url4.2 headers4.3 params4.4 proxies4.5 verify4.6 timeout4.7 cookies4.8 身份验证 3、测试代码3.1 获取网页HTML&#xff08;get&#xff09;3.2 获取网页HTML&#xff08;带he…

【LeetCode热题100】打卡第26天:最大矩形

文章目录 最大矩形⛅前言&#x1f512;题目&#x1f511;题解 最大矩形 ⛅前言 大家好&#xff0c;我是知识汲取者&#xff0c;欢迎来到我的LeetCode热题100刷题专栏&#xff01; 精选 100 道力扣&#xff08;LeetCode&#xff09;上最热门的题目&#xff0c;适合初识算法与数…

随着ChatGPT、文言一心的大火,未来可能的生活工作方式

前面的文章笼统的扯了一些ChatGPT、文言一心的差异化&#xff0c;感觉还是不够明白直观。特地找了一份资料&#xff0c;通过基础能力、进阶能力、和一些垂直领域的几百个各种问题&#xff0c;来对比分析两者的回答情况&#xff0c;让大家可以有个更接地气的了解。 由于问题太多…

无限脉动:释放音乐和区块链在音乐领域的力量

音乐是一种永恒的通用语言&#xff0c;它将人们聚集在一起&#xff0c;超越了边界&#xff0c;在我们灵魂深处产生共鸣&#xff0c;创造联系。在当今数字时代&#xff0c;随着区块链技术和去中心化网络的出现&#xff0c;音乐世界正在经历一场深刻的变革。 我们在与艺术家合作&…

动态规划 DP (二)

3.二维动态规划 1) 力扣https://leetcode.cn/problems/minimum-path-sum/第一行的的路径只与左边的元素有关&#xff0c;第一列的路径只与上面的元素有关。 除了第一行和第一列&#xff0c;其他元素的路径取决于左边和上面元素的最小值。 只要每次都选择值最小的路径&#…

2021电工杯数学建模B题解题思路(光伏建筑一体化板块指数发展趋势分析及预测)

目录 一、前言 二、问题背景 三、具体问题 四、解题思路 &#xff08;一&#xff09;整体思路 &#xff08;二&#xff09;问题一 &#xff08;三&#xff09;问题二 &#xff08;四&#xff09;问题三 &#xff08;五&#xff09;问题四 &#xff08;六&#xff09;…