代码如何工作以及原因

代码如何工作以及原因

我正在检查一个 shell 脚本并注意到下面的命令 - exec。exec 命令执行 cmdline,但我想知道:-/bin/bash这里的命令是什么。

cmdline="$@"
    exec ${cmdline:-/bin/bash}

答案1

代码如何工作以及原因

这里有三件主要的事情:

  • $@是特殊的 shell 变量,可扩展到脚本的所有命令行参数
  • ${cmdline:-/bin/bash}是参数扩展结构之一;如果cmdline变量未设置或为空,则整个${}部分将被替换为符号后面的内容-,在本例中/bin/bash;这有点像其他编程语言中的 if 语句或三元运算符的简写(不完全是,但足以进行比较)
  • exec用于生成一个将超越当前进程 PID 的进程,即简单地用脚本进程替换其中的内容${}

将所有这些放在一起,代码只需获取命令行参数并运行它们,如果脚本没有命令行参数 - 您将获得交互式bashshell。请注意,您还可以将选项传递给exec文档中提到的 - 比较./exec_script.sh -c env./exec_script.sh env

理论上好,实践上不好

这种方法本身可能看起来很复杂,但exec包装脚本- 脚本在组织一切以运行实际命令之前设置环境并检查变量。此处的区别在于包装器脚本中设置命令 - 包装器脚本通常设置环境和参数以仅运行一个特定程序。

相比之下,此脚本旨在运行用户在命令行中输入的任何内容。这有一个问题因为 shell 的工作原理- 如果命令行参数包含特殊字符,您要运行的命令可能会中断。我的意思是:

# This is how it's supposed to work
$ printf 'one%stwo' $'\t'                                                              
one     two

# This is how it works with unquoted parameter expansion
$ ./exec_script.sh  printf 'one%stwo' $'\t'                                            
onetwo

想象一下,如果你尝试使用该脚本运行my_cool_command filename$'\t'with$'\t'tabs.txt; 最好的情况下 - 命令会中断,但如果你filenamewithtab.txt当前文件夹中还有文件,my_cool_command则会对完全错误的文件进行操作。引用参数扩展也无济于事,因为它会中断:

$ ./exec_script.sh  printf 'one%stwo' $'\t'                                            
./exec_script.sh: line 4: exec: printf one%stwo     : not found

相关文件

以下是bash(版本 4.3)手册中有关参数扩展的相关部分:

${参数:-word}

使用默认值。如果参数未设置或为空,则替换单词的扩展。否则,替换参数的值。

“特殊参数”部分:

@ 扩展为位置参数,从 1 开始。当扩展发生在双引号内时,每个参数都会扩展为一个单独的单词。也就是说,“$@”相当于“$1”“$2”……如果双引号扩展发生在单词内,则第一个参数的扩展与原始单词的开头部分连接,最后一个参数的扩展与原始单词的末尾部分连接。当没有位置参数时,“$@”和 $@ 扩展为空(即它们被删除)。

来自“Shell 内置命令”部分:

exec [-cl] [-a 名称] [命令 [参数]]

如果指定了命令,它将替换 shell。不会创建新进程。参数将成为命令的参数。如果指定了 -l 选项,shell 会在传递给命令的第零个参数开头放置一个破折号。这就是 login(1) 所做的。-c 选项导致在空环境下执行命令。如果指定了 -a,shell 会将 name 作为第零个参数传递给执行的命令。如果由于某种原因无法执行命令,非交互式 shell 会退出,除非启用了 execfail shell 选项。在这种情况下,它返回失败。如果无法执行文件,交互式 shell 会返回失败。如果未指定命令,任何重定向都会在当前 shell 中生效,返回状态为 0。如果存在重定向错误,则返回状态为 1。

结论和想法

这个脚本本身在理论上有一个很好的想法,但在实践中却很糟糕。该exec命令在包装器脚本中运行良好,事实上,作为 Unix & Linux 网站上的顶级用户之一, 吉尔斯提到“...exec 还节省了一些内存(和其他资源,如 PID 等),因为没有必要保留一个没有其他事情要做的额外 shell”。但在这种情况下,脚本旨在重新发明轮子并做 shell 已经做得足够好的事情 - 即运行带参数的命令。

相关内容