The Uses of the Exec Command in Shell Script

一、概述

当我们创建 Bash 脚本时,我们可能希望将所有 echo 语句的输出重定向到一个日志文件中,而无需在每个 echo 语句之后显式指定重定向运算符和日志文件名。 Bash exec 命令是一个强大的内置实用程序,可用于此目的。

在本教程中,我们将了解如何使用 exec 命令将错误和输出日志添加到 shell 脚本。我们还将探索该命令在 shell 脚本中的其他用途。

2. 基础

每当我们在 Bash shell 中运行任何命令时,都会默认创建一个子 shell,并生成一个新的子进程来执行该命令。但是,当使用 exec 时,exec 之后的命令会替换当前的 shell。这意味着没有创建子shell,并且当前进程被这个新命令替换。

让我们做一个实验来更好地理解它:

$ pstree -p
init(1)─┬─init(52)───bash(53)
        ├─init(78)───bash(79)───pstree(108)
        └─{init}(7)
$ echo $$
79
$ exec sleep 300

我们使用 echo $$ 和 pstree 命令检查了当前 shell 的 PID,然后使用 exec 执行了 300 秒的休眠。现在让我们切换到另一个终端来检查进程列表:

$ ps -aef | grep $USER
user1       53    52  0 23:37 tty2     00:00:00 -bash
user1       79    78  0 23:39 tty1     00:00:00 sleep 300
user1      111    53  0 23:40 tty2     00:00:00 ps -aef
user1      112    53  0 23:40 tty2     00:00:00 grep --color=auto 

正如我们所见,最初分配给 Bash 的 PID 79 现在分配给了 sleep 命令。

我们还将观察到,在 300 秒的睡眠结束后,PID 为 79 的会话(终端)退出,因为 shell 被 exec 命令替换,并且它的执行已经完成。

3. 使用 exec 命令替换进程

使用不同的命令覆盖现有进程可能是一个强大的工具。让我们用其他一些例子来探讨这个想法。

3.1 用户登录配置文件

假设 Bash 不是我们 Linux 机器的默认 shell。有趣的是,使用 exec 命令,我们可以将内存中的默认 shell 替换为 Bash shell,方法是将其添加到用户的登录配置文件中:

exec bash

在某些情况下,我们希望将特定程序或菜单添加到用户的登录配置文件(.bashrc 或 .bash_profile),在这种情况下,我们可以阻止用户在程序退出后拥有 Bash 提示访问权限,而不管其退出状态:

exec operations_menu.sh

3.2.脚本内的程序调用

我们可以使用 exec 在脚本中调用脚本或其他程序来覆盖内存中的现有进程。这节省了创建的进程数量,从而节省了系统资源。当我们不想在子脚本或程序执行后返回主脚本时,此实现特别有用:

#! /bin/bash

while true
do
   echo "1. Disk Stats "
   echo "2. Send Evening Report "
   read Input
   case "$Input" in
      1) exec df -kh ;;
      2) exec /home/SendReport.sh  ;;
   esac
done

在这个简单的用户输入驱动脚本中,我们在不同的菜单选项中执行了 df 命令和使用 exec 的脚本。

4. 文件描述符和使用 exec 命令登录 Shell 脚本

exec 命令是一个强大的工具,用于操作文件描述符 (FD)、在脚本中创建输出和错误日志记录,只需极少的更改。在 Linux 中,默认情况下,文件描述符 0 是 stdin(标准输入),1 是 stdout(标准输出),2 是 stderr(标准错误)。

4.1在脚本中记录

我们可以动态打开、关闭、复制stdout来实现日志操作。让我们将标准输出(FD 1)重定向到日志文件:

#! /bin/bash
script_log="/tmp/log_`date +%F`.log"
exec 1>>$script_log
echo "This will be written into log file rather than terminal.."
echo "This too.."

我们检查了如何将标准输出写入文件,现在让我们检查如何将标准错误写入同一个文件:

#! /bin/bash
script_log="/home/shubh/log_`date +%F`.log"
exec 1>>$script_log
exec 2>&1
datee
echo "Above command is wrong, error will be logged in log file"
date
echo "Output of correct date command will also be logged in log file, including these echo statements"

这里我们将stderr(2)复制到stdout(1),stdout已经改成写入日志文件了。

4.2.将标准输入更改为从文件中读取

让我们创建一个示例输入文件:

$ cat input_csv
SNo,Quantity,Price,Value
1,2,20,40
2,5,10,50
3,1,70,70

现在让我们运行一个示例来读取我们创建的文件:

#! /bin/bash
exec < input_csv
read row1
echo -n "The contents of first line are: "
echo $row1
echo -n "The contents of second line are: "
read row2
echo $row2

这就是我们得到的:

The contents of first line are: SNo,Quantity,Price,Value
The contents of second line are: 1,2,20,40

4.3.更改文件描述符并恢复默认值

我们还可以打开和关闭新的文件描述符以读取和写入文件。让我们使用与上一节相同的输入文件来演示这一点:

#! /bin/bash
exec 3< input_csv
read -u 3 row1
echo $row1
exec 3<&-
exec 4>&1
exec > out.txt
echo "Output will be logged in out.txt"
exec 4>&-

在这里,我们首先在 FD 3 上打开输入文件,从文件中读取,然后在终端(默认为标准输出)上打印其内容。最后,我们使用 &- 关闭 FD 3。当此脚本执行时,输出如下:

SNo,Quantity,Price,Value

此外,该脚本还会创建一个输出文件 out.txt:

$ cat out.txt
Output will be logged in out.txt

请注意,脚本的输出仅包含第一个 echo 语句。有趣的是,在第一个 echo 语句之后,我们将 stdout 复制到 FD 4 并将其重定向到另一个文件。后来,在最后一行,我们通过关闭 FD 4 重新获得了对 stdout 的访问权限。

5. 在干净的环境中运行脚本

我们可以使用 -c 选项重置所有环境变量以进行干净运行:

exec -c printenv

由于 printenv 命令列出了环境变量,因此在此处将其作为 exec 命令的参数将打印一个空输出。

6. 使用 Find 命令

exec 选项可用于对 find 命令找到的文件执行 grep、cat、mv、cp、rm 等操作。让我们使用我们文章中关于 find 命令的示例来查找“src”目录中包含“interface”一词的所有 .java 文件:

find src -name "*.java" -type f -exec grep -l interface {} \;

在这里,我们指定了选项 -type f 以仅查找常规文件。此后,我们使用 -exec 选项对 find 命令返回的文件列表执行 grep 命令。注意末尾的分号会导致对每个文件执行 grep 命令,一次一个,因为 {} 被当前文件名替换。另请注意,需要使用反斜杠来使分号不被 shell 解释。

7. 结论

在本教程中,我们看到了 Bash 内置 exec 命令在 shell 脚本中的各种用法。

简而言之,它是流程替换的强大工具。具体来说,它在脚本中与文件描述符的使用使其成为可用于灵活脚本日志记录的最强大的工具之一。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值