深入理解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

相关推荐
云计算练习生12 小时前
linux shell编程实战 10 Git工具详解与运维场景实战
linux·运维·git
虚伪的空想家14 小时前
KVM的ubuntu虚机如何关闭安全启动
linux·安全·ubuntu
t1987512820 小时前
在Ubuntu 22.04系统上安装libimobiledevice
linux·运维·ubuntu
skywalk816320 小时前
linux安装Code Server 以便Comate IDE和CodeBuddy等都可以远程连上来
linux·运维·服务器·vscode·comate
晚风吹人醒.21 小时前
缓存中间件Redis安装及功能演示、企业案例
linux·数据库·redis·ubuntu·缓存·中间件
Hard but lovely21 小时前
linux: pthread库的使用和理解
linux
这儿有一堆花1 天前
Kali Linux:探测存活到挖掘漏洞
linux·运维·服务器
松涛和鸣1 天前
从零开始理解 C 语言函数指针与回调机制
linux·c语言·开发语言·嵌入式硬件·排序算法
皮小白1 天前
ubuntu开机检查磁盘失败进入应急模式如何修复
linux·运维·ubuntu
邂逅星河浪漫1 天前
【CentOS】虚拟机网卡IP地址修改步骤
linux·运维·centos