有一个类似的问题涉及“包装”场景,例如您想cd用调用 builtin 的命令替换cd。
但是,鉴于 shellshock 等人并知道 bash 从环境中导入函数,我进行了一些测试,但找不到cd从脚本中安全调用内置函数的方法。
考虑这个
cd() { echo "muahaha"; }
export -f cd
Run Code Online (Sandbox Code Playgroud)
在此环境中使用调用的任何脚本cd都会中断(考虑类似 的效果cd dir && rm -rf .)。
有用于检查命令类型的命令(方便地称为type)和用于执行内置版本而不是函数的命令(builtin和command)。但是,瞧,这些也可以使用函数覆盖
builtin() { "$@"; }
command() { "$@"; }
type() { echo "$1 is a shell builtin"; }
Run Code Online (Sandbox Code Playgroud)
将产生以下结果:
$ type cd
cd is a shell builtin
$ cd x
muahaha
$ builtin cd x
muahaha
$ command cd x
muahaha
Run Code Online (Sandbox Code Playgroud)
有什么方法可以安全地强制 bash 使用内置命令,或者至少检测到命令不是内置命令,而无需清除整个环境?
我意识到如果有人控制了您的环境,您无论如何都可能被搞砸了,但至少对于别名,您可以选择不通过在别名\之前插入 a 来调用别名。
mr.*_*tic 16
Olivier D几乎是正确的,但您必须POSIXLY_CORRECT=1在运行之前进行设置unset。POSIX 有一个Special Built-ins的概念,而bash 支持这个。unset就是这样一种内置。搜索SPECIAL_BUILTIN在builtins/*.c在bash的源列表,它包括set,unset,export,eval和source。
$ unset() { echo muahaha-unset; }
$ unset unset
muahaha-unset
$ POSIXLY_CORRECT=1
$ unset unset
Run Code Online (Sandbox Code Playgroud)
流氓unset现在已从环境中删除,如果您取消设置command, type,builtin那么您应该能够继续,但unset POSIXLY_CORRECT如果您依赖于非 POSIX 行为或高级 bash 功能。
但这并没有解决别名,因此您必须使用\unset以确保它在交互式 shell 中工作(或始终有效,以防万一expand_aliases)。
对于偏执狂,我认为这应该可以解决所有问题:
POSIXLY_CORRECT=1
\unset -f help read unset
\unset POSIXLY_CORRECT
re='^([a-z:.\[]+):' # =~ is troublesome to escape
while \read cmd; do
[[ "$cmd" =~ $re ]] && \unset -f ${BASH_REMATCH[1]};
done < <( \help -s "*" )
Run Code Online (Sandbox Code Playgroud)
( while, do,done和[[是保留字,不需要预防措施。) 请注意,我们使用unset -f的是确保取消设置函数,尽管变量和函数共享相同的命名空间,但两者可能同时存在(感谢 Etan Reisner)在这种情况下取消设置两次也可以解决问题。您可以将函数标记为只读,bash 不会阻止您取消设置只读函数直到并包括 bash-4.2,bash-4.3 确实会阻止您,但它在POSIXLY_CORRECT设置时仍然尊重特殊的内置函数。
readonlyPOSIXLY_CORRECT不是一个真正的问题,这不是一个布尔值或标志,它的存在会启用 POSIX 模式,因此如果它作为只读存在,您可以依赖 POSIX 功能,即使该值为空或 0。您只需要以与上述不同的方式取消设置有问题的功能,可能需要进行一些剪切和粘贴:
\help -s "*" | while IFS=": " read cmd junk; do echo \\unset -f $cmd; done
Run Code Online (Sandbox Code Playgroud)
(并忽略任何错误)或从事其他一些脚本操作。
其他注意事项:
function是一个保留字,它可以被别名化,但不能被函数覆盖。(别名function有点麻烦,因为作为绕过它的方式\function 是不可接受的)[[,]]是保留字,它们可以是别名(将被忽略)但不能被函数覆盖(尽管函数可以如此命名)(( 不是函数的有效名称,也不是别名我意识到如果有人控制了你的环境,你可能无论如何都被搞砸了
就是那个。如果您在未知环境中运行脚本,那么各种事情都可能出错,首先是LD_PRELOAD导致 shell 进程在读取您的脚本之前执行任意代码。试图从脚本内部抵御敌对环境是徒劳的。
十多年来,Sudo 一直通过删除任何看起来像 bash 函数定义的内容来净化环境。自Shellshock以来,在不完全信任的环境中运行 shell 脚本的其他环境也纷纷效仿。
您无法在不受信任的实体设置的环境中安全地运行脚本。所以担心函数定义是没有成效的。清理您的环境,并在此过程中将 bash 解释为函数定义的变量。