深入理解linux shell 中的exec内置命令&ubuntu bash

概览

每当我们在Bash shell 中运行任何命令时,默认情况下都会创建一个子 shell,并生成(分叉)一个新的子进程来执行该命令。但是,当使用 exec时,exec 后面的命令将替换当前 shell。这意味着不会创建任何子 shell,并且当前进程将替换为此新命令。

进程替换实验

  1. 先查看当前shell的PID

    bash 复制代码
    jagitch@jagitch-MS-7B93:tmp$ echo $$
    280513
  2. 打开第二个shell,查看shell 1的进程信息

    bash 复制代码
    jagitch@jagitch-MS-7B93:tmp$ ps -aef | grep 280513
    jagitch   280513   22748  0 11:37 pts/0    00:00:00 bash
    jagitch   281157  273610  0 11:38 pts/1    00:00:00 grep --color=auto 280513
  3. 在shell 1中执行exec命令

    bash 复制代码
    jagitch@jagitch-MS-7B93:tmp$ exec sleep 40
  4. 在shell 2中再次查看shell 1的进程信息

    bash 复制代码
    jagitch@jagitch-MS-7B93:tmp$ ps -aef | grep 280513
    jagitch   280513   22748  0 11:37 pts/0    00:00:00 sleep 40
    jagitch   281573  273610  0 11:38 pts/1    00:00:00 grep --color=auto 280513

    此时发现280513这个进程由之前的bash替换成了sleep 40,说明exec执行地命令不会创建子进程,而是替换掉当前进程的程序。这样可以达到节约计算机资源的目的。

  5. 等shell 1中地exec命令结束后,发现shell 1退出了,此时在shell 2中查看shell 1的进程ID

    bash 复制代码
    jagitch@jagitch-MS-7B93:tmp$ ps -aef | grep 280513
    jagitch   281749  273610  0 11:39 pts/1    00:00:00 grep --color=auto 280513

    此时发现shell 1那个进程已经被销毁了,因为默认的bash进程被exec替换为了sleep命令,这个命令执行完后就会退出,而之前那个shell进程会一直循环解释执行用户输入的命令,它不会退出被销毁。

exec的常用用法

  1. 脚本中进行命令替换

    bash 复制代码
    jagitch@jagitch-MS-7B93:tmp$ cat ./execdemo.sh 
    #!/bin/bash
    
    echo first
    exec echo second
    echo last
    
    jagitch@jagitch-MS-7B93:tmp$ chmod +x ./execdemo.sh 
    jagitch@jagitch-MS-7B93:tmp$ ./execdemo.sh 
    first
    second

    我们可以发现last没有被输出,因为./execdemo.sh在一个子进程中执行,第一个echo正常输出,但是遇到exec echo second后,这个子进程就被替换成echo second了,执行完这条命令该进程就退出销毁了,自然就不会执行后面的echo last了。

  2. 使用exec进行日志记录

    bash 复制代码
    jagitch@jagitch-MS-7B93:tmp$ cat execlog.sh 
    #!/bin/bash
    
    LOG_FILE="output.log"
    
    exec &> "$LOG_FILE"
    
    echo "1. script started at $(date +'%Y-%m-%d')"
    
    echo "2. find all .txt files in current dir"
    find -type f -name "*.txt"
    
    echo "3. make some error"
    cat hello
    
    echo "4. script finished at $(date +'%Y-%m-%d')"
    
    jagitch@jagitch-MS-7B93:tmp$ bash execlog.sh
    jagitch@jagitch-MS-7B93:tmp$ cat output.log
    1. script started at 2024-06-28
    2. find all .txt files in current dir
    ./2.txt
    ./1.txt
    ./favorite colors.txt
    3. make some error
    cat: hello: 没有那个文件或目录
    4. script finished at 2024-06-28

    execlog.sh脚本中使用`exec &> "$LOG_FILE"将标准输出和标准错误都重定向到指定地文件中。

  3. 使用exec操作文件描述符

    bash 复制代码
    jagitch@jagitch-MS-7B93:tmp$ cat execfd.sh
    #!/bin/bash
    
    exec 3> fruit.txt
    exec 1>&3
    echo "apple"
    echo "orange"
    exec 3>&-
    jagitch@jagitch-MS-7B93:tmp$ bash execfd.sh
    jagitch@jagitch-MS-7B93:tmp$ cat fruit.txt 
    apple
    orange

    exec 3> fruit.txt将文件描述符重定向到fruit.txt文件

    exec 1>&3把标准输出重定向到文件描述符为3的文件中

    exec 3>&-的意思是关闭文件描述符

每一次点赞,都是你独特的味道。每一次关注,都是我前行的动力。感谢有你,一起成长!

推荐阅读

1. 互联网、因特网和万维网傻傻分不清,一文带你彻底理解计算机中的各种网络

2. 十分钟带你入门Go语言(Golang)开发

3. 超级详细的Github双重验证开启教程&github Two-factor authentication

相关推荐
南境十里·墨染春水2 小时前
linux学习笔记 网络编程——Socket入门与TCP客户端/服务器实现
linux·服务器·网络
Yupureki4 小时前
《Linux网络编程》6.UDP原理
linux·运维·服务器·网络·udp
楼田莉子4 小时前
Linux网络:NAT_代理
linux·运维·服务器·开发语言·c++·后端
烛衔溟4 小时前
TypeScript 索引签名、只读数组与 keyof / typeof 入门
linux·ubuntu·typescript
笨笨饿5 小时前
#79_NOP()嵌入式C语言中内联汇编宏的抽象封装模式研究
linux·c语言·网络·驱动开发·算法·硬件工程·个人开发
fish_xk5 小时前
Linux的权限
linux·运维·服务器
嵌入式×边缘AI:打怪升级日志7 小时前
Linux 驱动与应用开发核心自测题库(面试官问答完整版)
linux·运维·php
薛定谔的悦8 小时前
储能充放电状态机执行逻辑详解
linux·数据库·能源·储能·bms
嵌入式×边缘AI:打怪升级日志9 小时前
Tina SDK Linux Kernel 基本使用(实战篇:为7寸RGB LCD触摸屏添加驱动支持).md
linux·运维·服务器
前端之虎陈随易9 小时前
为什么今天还会有新语言?MoonBit 想解决什么问题?
大数据·linux·javascript·人工智能·算法·microsoft·typescript