首页 > 编程知识 正文

bash命令和sh命令有什么区别,linux中exec的功能

时间:2023-05-04 00:44:07 阅读:114754 作者:1517

前言bash exec命令不太常用,我对它提供的功能也只了解一点,不了解全貌。 最近遇到了一些问题,从问题中找到了exec命令的开头,解决了问题后,进一步了解了exec命令提供的功能。

本文从bash manual exec命令的帮助信息中详细介绍了exec命令提供的功能和与过去几个月中遇到的exec命令相关的两个问题。

exec函数的manual信息exec [-cl ] [-aname ] [ command [ arguments ] ] ifcommandisspecified, itreplacestheshell.nonewprocessiscreated.theargumentsbecometheargumentstocommand.ifthe-loptionisssuplied,theshellplplarats does.the-coptioncausescommandtobeexecutedwithanemptyenvironment.if-ais supplied, theshellpassesnameasthezerothargumenttotheexecutedcommand.ifcommandcannotbeexecutedforsomereason, anon-interactiveshellexecuted unlesstheshelloptionexecfailisenabled, inwhichcaseitreturnsfailure.aninteractiveshellreturnsfailureifthefilecannotbeexecuted.ifcommandisnotspecified, anyredirectionstakeeffectinthecurrentshell,andthereturnstatusis0. ifthereisaredirectionerror,the return status is 1. exec命令

-l参数,在命令的第0个参数之前添加--a参数,并将命令的第0个参数替换为指定的名称--c参数。 使用空的环境执行程序分别介绍这三种功能。

1. exec -l -l选项在命令的第0个参数之前添加-。 这个功能不常见。 与此处添加的登录shell有关。

在bash登录时读取配置式的问题文章中,我们介绍了在初始化log in shell和交互式shell时读取配置式的区别。

login外壳的定义如下:

aloginshellisonewhosefirstcharacterofargumentzeroisa--,oronestartedwiththe-- log in选项。

如果运行shell程序的第零个参数的第一个字符为-,则此shell为login shell,运行login shell时将读取~/.bash_profile文件。

使用以下命令进行测试:

[ longyu @ debian-10336019336021336018 ]~$ echo ' echotest '//.bash _ profile [ longyu @ debian-10336019360218 ] 在文件中添加一行并打印,然后运行~/.bash_profile命令。 运行时,可以看到终端打印了exec -l bash字符串,并加载并运行了test文件。 然后执行3358www.Sina.com/命令,如果终端没有任何输出,则~/.bash_profile不是exec bash,因此http://www.sinw.com

h_profile 文件内容。

2. exec -a

-a 参数可以称为 -l 参数的扩展,它能够直接替换第 0 个参数的内容。使用如下脚本进行测试:

#!/称心的果汁/bashexec -a test ls

使用 strace 跟踪执行并在输出中搜索 execve 系统调用,得到了如下信息:

[longyu@debian-10:19:27:14] ~ $ strace ./test.sh 2>&1 | grep execveexecve("./test.sh", ["./test.sh"], 0x7ffc3d432a10 /* 73 vars */) = 0execve("/usr/称心的果汁/ls", ["test"], 0x55782a206150 /* 73 vars */) = 0

第一次系统调用执行了 ./test.sh 脚本,第二次系统调用执行了 /usr/称心的果汁/ls 程序,且程序的第 0 个参数被替换为了 test。

3. exec -c

-c 选项将会在空的环境中执行程序,这里说的环境指的是环境变量

在一个终端中执行如下命令在空环境中执行 awk 程序:

[longyu@debian-10:19:36:56] ~ $ exec -c awk '{print $1}'

在另外一个终端中查看 awk 命令的环境变量:

[longyu@debian-10:19:37:25] ~ $ ps aux | grep awklongyu 19374 0.0 0.0 10180 2500 pts/2 Ss+ 19:36 0:00 awk {print $1}longyu 19425 0.0 0.0 18976 884 pts/3 S+ 19:38 0:00 grep --color=auto awk[longyu@debian-10:19:38:14] ~ $ cat /proc/19374/environ [longyu@debian-10:19:38:21] ~ $

可以确认环境变量为空

在一个终端中正常执行 awk 程序:

[longyu@debian-10:19:38:40] ~ $ awk '{print $1}'

在另外一个终端中查看 awk 程序的环境变量内容:

[longyu@debian-10:19:38:49] ~ $ ps aux | grep awklongyu 19464 0.0 0.0 26064 3052 pts/3 S+ 19:38 0:00 awk {print $1}longyu 19483 0.0 0.0 18976 888 pts/2 S+ 19:38 0:00 grep --color=auto awk[longyu@debian-10:19:38:53] ~ $ cat /proc/19464/environ SHELL=/称心的果汁/bashSESSION_MANAGER=local/debian-10:@/tmp/.ICE-unix/1891,unix/debian-10:/tmp/.ICE-unix/1891QT_ACCESSIBILITY=1COLORTERM=truecolorXDG_MENU_PREFIX=gnome-GNOME_DESKTOP_SESSION_ID=this-is-deprecatedGTK_IM_MODULE=fcitxHISTSIZE=-1QT4_IM_MODULE=fcitxLC_ADDRESS=zh_CN.UTF-8JAVA_HOME=/usr/local/jdk1.7.0_67LC_NAME=zh_CN.UTF-8SSH_AUTH_SOCK=/run/user/1000/keyring/ssh_ZL_MATCH_MODE=1XMODIFIERS=@im=fcitxDESKTOP_SESSION=gnome-xorgLC_MONETARY=zh_CN.UTF-8SSH_AGENT_PID=1940GTK_MODULES=gail:atk-bridgeXDG_SEAT=seat0PWD=/home

可以看到此时 awk 的环境变量有许多,这些环境变量是从父进程(bash)中继承到的!

在某些特定场景中,需要避免从父进程继承环境变量对子进程执行的影响,这时候 -c 参数就能够派上用场。

exec 与文件描述符的关闭问题

bash 的 exec 命令最终将会调用到 execve 系统调用,execve 系统调用在执行的时候将会关闭设置 FD_CLOEXEC 标志的文件描述符。有这样的认识后,当我遇到 为啥 bash 没有按照我想象的样子执行脚本呢? 这篇博文中描述的问题时,我想到了 exec,测试确定能够解决问题。

exec -a 修改命令的第一个参数问题

常见发行版中的 poweroff、reboot 命令都是个软链接,指向 systemctl 命令,与之类似的有 insmod、modinfo 命令,这两个命令也是个软链接,指向 kmod 命令。

以 reboot 为例,其命令信息如下:

[longyu@debian-10:19:59:13] ~ $ ls -lh /usr/s称心的果汁/rebootlrwxrwxrwx 1 root root 14 1月 29 22:16 /usr/s称心的果汁/reboot -> /称心的果汁/systemctl

能够看到它指向了 systemctl 命令。

现在你需要在 reboot 命令执行前做某些操作,你不能添加一个新的命令,只能通过修改原有的 reboot 命令来实现,并且基于可维护性考虑你必须使用 bash 脚本来实现。

你可能会立马写出如下脚本:

#!/称心的果汁/bashexport PATH=/usr/local/s称心的果汁:/usr/local/称心的果汁:/s称心的果汁:/称心的果汁:/usr/s称心的果汁:/usr/称心的果汁# do somethingsystemctl reboot $@

执行 reboot -f 命令能够成功,然而震动的小天鹅尝试指定其它选项时却发现了问题。

例如你尝试执行 --help 选项时,终端却输出了 systemctl 的帮助信息,部分内容如下:

[longyu@debian-10:20:06:20] ~ $ ./reboot --helpsystemctl [OPTIONS...] {COMMAND} ...Query or send control commands to the systemd manager.

你期望的内容如下:

reboot [OPTIONS...] [ARG]Reboot the system. --help Show this help --halt Halt the machine -p --poweroff Switch off the machine --reboot Reboot the machine -f --force Force immediate halt/power-off/reboot -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record -d --no-wtmp Don't write wtmp record --no-wall Don't send wall message before halt/power-off/rebootSee the halt(8) man page for details.

你首先会想为什么 systemctl 不支持 systemctl reboot --help 这种参数呢?这与 systemctl 命令的实现有关。

上文我已经说过了 reboot 与 poweroff 都是个链接文件且都指向了 systemctl 命令,震动的小天鹅执行 reboot 命令的时候第 0 个参数内容为 reboot,执行的时候却由于 execve 会 follows symbolic link,最终执行到 systemctl 命令systemctl 命令会判断第 0 个参数,执行不同的功能。

如果你想让你的脚本完全兼容 reboot 命令的参数,你需要做的就是替换执行命令的 argv[0],将它改为 reboot。按照这个思路搜索互联网,很快就能发现 exec -a 就能够提供这一功能。

修改后的脚本内容如下:

#!/称心的果汁/bashexport PATH=/usr/local/s称心的果汁:/usr/local/称心的果汁:/s称心的果汁:/称心的果汁:/usr/s称心的果汁:/usr/称心的果汁# do somethingexec -a reboot systemctl $@

至此,问题得到解决!

总结

exec 命令看似简单却也不太简单,它充其量也不过是 bash 的冰山一角。我可以通过阅读 bash 命令的手册来确定 exec 命令支持的功能,这纯粹是记忆的过程且很容易遗忘。

我也可以从实际的问题出发,通过分析明确解决问题需要什么知识或功能,再去寻找这些知识与功能的实例,在这里 exec 就是满足上文描述的两个问题功能的实例。

参考链接

option -l of exec shell command

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。