如何防止Bash使用内建命令?

20

我正在尝试修复一个使用echo的脚本,它使用的是内置命令而不是命令,我该如何防止这种情况发生?

我知道可以使用/bin/echo来强制使用它,但我不想硬编码路径(以保证可移植性)。

我考虑使用以下内容:

$ECHO=`which echo`
$ECHO -e "text\nhere"

但是which echo返回:"echo: shell内置命令"。


我最终定义了一个echo函数,该函数使用env,正如@Kenster所建议的那样。这样一来,我就不需要修改脚本中对echo的调用。

echo() {
  env echo $*
}

# the function is called before the built-in command.
echo -en "text\nhere"

1
内置命令而不是命令 WTF? - ForceBru
1
有一些命令(例如 echo)可以相当可靠地硬编码路径。 - Etan Reisner
1
如果你关心可移植性,使用 printf 而不是任何形式的 echo - chepner
1
@MichaelJaros 非内置的 echo 支持 -e 添加转义序列和 -n 防止尾随换行。 - eloyesp
4
一篇被删除的(也是错误的)回答建议使用command内置命令:command echo ...。这样做行不通,因为command绕过了shell函数,但不会绕过内置命令。我在这里提到这一点是为了那些无法阅读已删除答案并可能尝试使用command命令的人的好处。 - Keith Thompson
显示剩余4条评论
2个回答

18

使用env程序。Env是一个命令,它可以使用可能修改过的环境启动另一个程序。因为env是一个程序,所以它没有访问shell内置命令、别名等的权限。

这个命令将在您的命令路径中运行echo程序:

$ env echo foo

你可以通过使用strace监视系统调用来验证这一点,同时运行echoenv echo

$ strace -f -e trace=process bash -c 'echo foo'
execve("/bin/bash", ["bash", "-c", "echo foo"], [/* 16 vars */]) = 0
arch_prctl(ARCH_SET_FS, 0x7f153fa14700) = 0
foo
exit_group(0)                           = ?

$ strace -f -e trace=process bash -c 'env echo foo'
execve("/bin/bash", ["bash", "-c", "env echo foo"], [/* 16 vars */]) = 0
arch_prctl(ARCH_SET_FS, 0x7f474eb2e700) = 0
execve("/usr/bin/env", ["env", "echo", "foo"], [/* 16 vars */]) = 0
arch_prctl(ARCH_SET_FS, 0x7f60cad15700) = 0
execve("/usr/local/sbin/echo", ["echo", "foo"], [/* 16 vars */]) = -1 ENOENT (No such file or directory)
execve("/usr/local/bin/echo", ["echo", "foo"], [/* 16 vars */]) = -1 ENOENT (No such file or directory)
execve("/usr/sbin/echo", ["echo", "foo"], [/* 16 vars */]) = -1 ENOENT (No such file or directory)
execve("/usr/bin/echo", ["echo", "foo"], [/* 16 vars */]) = -1 ENOENT (No such file or directory)
execve("/sbin/echo", ["echo", "foo"], [/* 16 vars */]) = -1 ENOENT (No such file or directory)
execve("/bin/echo", ["echo", "foo"], [/* 16 vars */]) = 0
arch_prctl(ARCH_SET_FS, 0x7f0146906700) = 0
foo
exit_group(0)                           = ?

1
我最终采用了您的解决方案,但使用一个函数来简化实现:echo() { env echo $* }非常好用! - eloyesp

13

你可以禁用内置的回显功能:

enable -n echo

现在只需执行echo anything即可运行外部版本。它仅影响当前的脚本进程,因此您可以在脚本中安全地执行它。


1
酷,我不知道那个。enable是内置命令吗?它在sh中工作吗? - eloyesp
6
enable 是 bash 中的内置命令(当然,如果你运行 enable -n enable 命令,就会失效!)。在 POSIX 的 sh 中无法使用该命令,因为 POSIX 没有真正意义上的内置命令和外部命令之分。 - that other guy
1
当我想到将 builtinenable 结合在一起时,脑海中浮现的第一件事是 enable -n enable :D。 - Samveen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接