【shell】遇到错误退出set -e|set -u|set -x|shell 退出时执行|捕捉信号trap

2023-05-16

目录

遇到错误退出

简介和使用

set -e 的陷阱

1,管道命令

2, grep匹配不到会导致退出

shell退出时执行|接收信号|trap

用途

trap介绍

列出所有信号的数值和名字

trap的注意事项

遇到错误退出

简介和使用

set -e      #脚本里面有返回值非0命令/运行失败的命令 就退出

set -u       #如果遇到不存在的变量,就退出

sh -x  my.sh 回整个脚本都输出调试信息,太多了

使用set -x开启某一段的调试信息:

set -x 开始调试;

set +x 结束调试;

-x还有另一种写法-o xtrace。

set -o xtrace

set -e 的陷阱

1,管道命令

set -o pipefail

set -e有一个例外情况,就是不适用于管道命令。
就是多个子命令通过管道运算符(|)组合成为一个大的命令。Bash 会把最后一个子命令的返回值,作为整个命令的返回值。即只要最后一个子命令不失败,管道命令总是会执行成功,因此它后面命令依然会执行,set -e就失效了。

例子:假如foo命令不存在

foo | echo a

foo是一个不存在的命令,但是foo | echo a这个管道命令会执行成功,导致脚本会继续往后执行

#!/bin/bash

set -e

for species in `something`;do
    ...
    for id in `something`;do
       cmd1 | cmd2 | grep sth
    done | cmd3 | cmd4 > somefile
done
cmd5

内层循环某一次grep失败,会导致整个内层循环退出,而由于内层循环与后面的管道形成了一个整体,这个整体的最后一个命令(重定向到somefile文件)不会失败,所以这个整体不会触发ERREXIT。外层循环可以顺利运行,遍历整个列表

摘自:http://t.csdn.cn/gRlFp

2, grep匹配不到会导致退出

#!/usr/bin/env bash
set -e
PID=$(ps -ef | grep "进程标识" | grep -v grep | awk '{print $2}')
echo "pid is: "$PID

如果没有相应的进程会因为第二个 grep :grep "进程标识"匹配不到,退出码 $? 为 1,set -e导至脚本退出,没有执行echo输出

解决办法:使用bash的分组命令功能:Grouping Commands

#!/usr/bin/env bash
set -e
PID=$(ps -ef | { grep "进程标识" || true; } | { grep -v grep || true; } | awk '{print $2}')
echo "pid is: "$PID

参考:linux shell set -e grep 匹配不到导致脚本退出问题https://blog.csdn.net/zswspock/article/details/119245835

下面的也能使得set -e 失效

command | grep -r ${str} | tee a.log

tee a.log 可以改变命令的执行后的返回值,而不改变命令本身的执行结果

shell退出时执行|接收信号|trap

(摘自:https://www.jianshu.com/p/07220a5d855a)

用途:

1,脚本退出时执行清理等

2,项目中的升级脚本可能耗时很长,没有输出像卡住,部署人员直接CTRL+C停掉升级脚本造成破坏。可以使用Shell的内建命令trap来忽略SIGINT这些信号,保证升级不会中断。

trap介绍

功能就是设置信号处理行为,trap的格式如下:

trap [-lp] [[arg] sigspec ...]
  • arg可以是shell命令或者自定义函数
  • sigspec 定义在<signal.h>中的信号名或者数值,SIG前缀是可选的,大小写不敏感,可以一个或多个

例子:

trap "echo 123" SIGINT   #设置ctrl+C 时执行echo 123

trap "echo 123" EXIT            #设置exit 退出时执行echo 123,EXIT也可以替换为0

trap "echo 123" RETURN     #在函数返回时,或者.source执行其他脚本返回时时执行echo 123

trap "echo 123" DEBUG        #在运行脚本前执行"echo 123",但对于函数仅在函数的第一条命令前执行一次

trap "echo 123" ERR              #在命令结果为非0时,执行trap设置的命令:echo 123

#!/bin/bash

foo()

{

echo "foo 1"

echo "foo 2"

}

trap "echo 123" DEBUG

foo

执行结果

123 # 在函数前执行一次

foo 1

foo 2

列出所有信号的数值和名字

trap -l:列出所有信号的数值和名字,类似于kill -l

[root@localhost ~]# trap -l

1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP

6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1

11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM

16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP

21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ

26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR

31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3

38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8

43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13

48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12

53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7

58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2

63) SIGRTMAX-1 64) SIGRTMAX

trap -p:列出通过trap设置的信号处理命令。

[root@localhost ~]# trap "echo INT" INT

[root@localhost ~]# trap -p INT

trap -- 'echo INT' SIGINT

trap "" sigspec:忽略sigspec指定的信号

trap "do something" sigspec:收到sigspec指定的信号时,do some thing后,继续执行后续命令。

trap sigspec or trap - sigspec:恢复sigspec指定的信号的默认行为

trap的注意事项

  • trap可以在收到信号前的任意位置设置,并非需要在脚本的第一行,但是shell是按照顺序执行语句的,不会优先执行trap

#!/bin/bash

trap -p INT # 不输出任何信息

trap "echo get signal" INT

  • 在函数中设置trap,也是全局生效的
  • 对于同一个信号,只有最后一次trap生效
  • trap只在本进程内有效,它的子进程不会继承trap的设置。
    main.sh
  • 如果子进程阻塞着,当通过kill直接杀死父进程时,只有等到子进程退出,父进程才会处理信号。kill -2 杀掉以下脚本的进程,此时需要等待10秒后,才会输出"get signal"。因为CTRL+C的信号是发送给进程组,此时sleep进程被INT信号中断了,所以立即输出了"get signal",可以用Kill -2 发送信号到进程组达到一样的效果。

#!/bin/bash

trap "get signal" INT

sleep 10

还有一个变通的方法就是把sleep放在后台进行,并用wait等待,wait是shell的内建命令,会被本进程收到的信号直接打断,此时sleep是继续在后台执行的。

#!/bin/bash

trap "get signal" INT

sleep 10 & wait $!

  • 处理SIGINT或者SIGQUIT时,需要特别注意。比如下面的脚本,CTRL+C后只是中断了一次sleep,当信号处理结束后,又会进入下一次sleep,这可能并不符合预期。

#!/bin/bash

trap "echo get signal" INT

sleep 10

sleep 10

需要在处理信号中,将信号处理恢复到默认,并以INT信号再次杀掉自己

#!/bin/bash

trap "echo get signal;trap - INT;kill -s INT "$$" " INT

sleep 10

sleep 10

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【shell】遇到错误退出set -e|set -u|set -x|shell 退出时执行|捕捉信号trap 的相关文章

随机推荐

  • 转载:配置darknet_ros实现yolo检测

    来自第三届华南农业大学人工智能协会 xff1a 会长部 麦彦恒出品 配置darknet ros实现yolo检测 M朗拿度的博客 CSDN博客
  • AUTOSAR(一)基本概述

    提示 xff1a 文章写完后 xff0c 目录可以自动生成 xff0c 如何生成可参考右边的帮助文档 文章目录 目录 文章目录 一 什么是AUTOSAR xff1f 二 为什么要使用AUTOSAR xff1f 三 AUTOSAR版本 一 什
  • 台达PLC与单片机的通讯

    最近由于工作需要用PLC与单片机通讯 xff0c 以此用PLC来控制单片机 xff0c 使单片机作为一个IO扩展模块来使用 这是第一次尝试自己写代码来使两个器件通讯 xff0c 故在此做一下笔记 xff0c 顺便巩固一下在这个过程中所学到的
  • VirtualBox 创建了备份(系统快照),如何恢复备份

    打开软件 xff0c 就进入了以下界面 这里并没有什么备份操作 xff0c 然后我们点开这个位置 点击备份就会到达这个页面 点击自己想要恢复的备份就可以了 xff0c 不过得先要关机
  • 详细讲解算术/范围编码(AC)

    算术编码 xff08 Arithmetic coding xff09 是一种无损数据压缩技术 xff0c 它能够将任意离散的符号串 xff08 如字母 像素值等 xff09 压缩为一个实数区间 xff0c 并可以通过解码还原出原始数据 范围
  • 50家大厂面试万字精华总结,数据库事务深入分析,最全指南

    什么是自旋锁和互斥锁 xff1f 由于CLH锁是一种自旋锁 xff0c 那么我们先来看看自旋锁是什么 xff1f 自旋锁说白了也是一种互斥锁 xff0c 只不过没有抢到锁的线程会一直自旋等待锁的释放 xff0c 处于busy waiting
  • MySQL万字精华总结!你连基础的JVM运行时内存布局都忘了?含面试题+答案

    前言 Netty 是一款基于 Java 的网络编程框架 xff0c 能为应用程序管理复杂的网络编程 多线程处理以及并发 Netty 隐藏了样板和底层代码 xff0c 让业务逻辑保持分离 xff0c 更加易于复用 使用 Netty 可以得到一
  • 【STM32】 AMS1117(稳压)模块

    目录 一 xff1a 介绍 二 xff1a 应用 三 xff1a AMS1117 3 3芯片实物图 四 xff1a 特性 五 xff1a 典型应用 六 xff1a 引脚分配 七 xff1a 可调 固定低压差线性稳压器结构 一 xff1a 介
  • 【网络】连接服务器失败(错误原因:Connection refused)| error 111: (111) Connection refused 原因分析

    服务器拒绝原因 xff1a connect 发起TCP连接请求被拒绝是由于目标服务器上无对应的监听套接字 xff08 IP amp amp PORT xff09 xff08 没有监听 无法创建 监听别的IP 端口 xff09 有几个可能性
  • 【C++软件开发】Linux相关面试题型

    一 xff1a Linux的I O模型介绍以及同步异步阻塞非阻塞的区别 xff08 超级重要 xff09 xff08 IO过程包括两个阶段 xff1a xff08 1 xff09 内核从IO设备读写数据和 xff08 2 xff09 进程从
  • 【C++】 STL详解

    目录 一 xff1a 泛型编程 二 xff1a 什么是STL 三 xff1a STL发展 四 xff1a STL组件 五 xff1a 容器 六 xff1a 类型成员 七 xff1a 适配器 八 xff1a 迭代器 九 xff1a 算法 十
  • 12.STM32freeRTOS---递归互斥信号量

    文章目录 前言一 创建递归互斥信号量二 释放递归互斥信号量三 获取递归互斥信号量四 官方例程总结 前言 递归互斥信号量可以看成是一个特殊的互斥信号量 对于互斥信号量 xff0c 获取了互斥信号量的任务就不能再次获取这个互斥信号量 xff0c
  • toString用法

    toString是定义在java lang Object的方法 xff0c 因此所有类都可以使用toString方法 xff0c 但是 toString方法本身返回的是地址信息而对于String Date File 包装类 等都重写了toS
  • 商医通项目总结

    一 项目概述 简介 尚医通即为网上预约挂号系统 xff0c 网上预约挂号是近年开展的一项便民就医服务 xff0c 旨在缓解看病难 挂号难的就医难题 网上预约挂号全面提供的预约挂号业务从根本上解决了这一就医难题 随时随地轻松挂号 xff0c
  • docker安装以及遇到的问题

    目录 一 docker安装 二 安装中可能碰到的问题 1 WSL 2 installation is incomplete 一 docker安装 docker官网下载 xff1a Docker Desktop Docker xff0c 下载
  • STM32MP157实验(三)——按键扫描和中断

    文章目录 按键扫描设计需求基础知识硬件设计STM32CubeIDE设计MX设置代码设计 实验结果 按键中断设计需求基础知识硬件设计STM32CubeIDE设计MX设置代码设计 总结 按键扫描 设计需求 通过按键扫描的方式实现 xff0c 按
  • 一篇博客实现嵌入式入门

    文章目录 前言最小系统和C语言最小系统原理图电源电路时钟电路复位电路调试 下载电路 嵌入式C语言基础知识数据类型const用法修饰变量修饰数组修饰指针修饰函数参数 作用域与static用法extern的用法volatile的用法struct
  • 驱动开发(一)——(单片机程序、Linux应用程序与驱动程序分析)

    文章目录 前言157准备工作配置交叉编译链编译内核编译解压glibc 单片机程序应用程序驱动程序三者的关系 前言 学习资料 xff0c 跟的韦东山老师的视频 xff0c 大家可以上百问网下载资料 百问网 我使用的开发板是STM32MP157
  • 驱动开发(五)——驱动设计思想(面向对象/分层/分离)

    文章目录 设计思想面向对象分层分离 实验手册资源驱动程序 led drv cled operations h芯片相关chip gpio cled resource h单板相关 board MP157 led c应用测试程序Makefile
  • 【shell】遇到错误退出set -e|set -u|set -x|shell 退出时执行|捕捉信号trap

    目录 遇到错误退出 简介和使用 set e 的陷阱 1 xff0c 管道命令 2 xff0c grep匹配不到会导致退出 shell退出时执行 接收信号 trap 用途 trap介绍 列出所有信号的数值和名字 trap的注意事项 遇到错误退