深入理解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 小时前
在UI界面内修改了对象名,在#include “ui_mainwindow.h“没更新
c++·qt·ubuntu·ui
地衣君5 小时前
RISC-V 开发板 + Ubuntu 23.04 部署 open_vins 过程
linux·ubuntu·risc-v
5:005 小时前
云备份项目
linux·开发语言·c++
码农101号6 小时前
Linux中shell编程表达式和数组讲解
linux·运维·服务器
云道轩6 小时前
升级centos 7.9内核到 5.4.x
linux·运维·centos
是小满满满满吗6 小时前
传输层:udp与tcp协议
linux·服务器·网络
爱学习的小道长6 小时前
Ubuntu Cursor升级成v1.0
linux·运维·ubuntu
EelBarb7 小时前
seafile:ubuntu搭建社区版seafile12.0
linux·运维·ubuntu
Xam_d_LM7 小时前
【Latex】Windows/Ubuntu 绘制 eps 矢量图通用方法(drawio),支持插入 Latex 数学公式
linux·ubuntu·科研·矢量图·drawio
Mintimate7 小时前
云服务器 Linux 手动 DD 安装第三方 Linux 发行版:原理与实战
linux·运维·服务器