ksh
针对 bash
的解决方法:确保 unset
具有其原始含义:
如果您知道 bash
将执行您的脚本,则此解决方法是安全的,但不幸的是无法保证。
此外,由于它修改了 shell 环境(删除别名和函数),因此不适用于旨在被引用的脚本。
如上所述,通常不希望在 Bash 的 POSIX 兼容模式下运行代码,但您可以临时激活它以确保 unset
不会被函数遮蔽:
#!/bin/bash
# *Temporarily* force Bash into POSIX compatibility mode, where `unset` cannot
# be shadowed, which allows us to undefine any `unset` *function* as well
# as other functions that may shadow crucial commands.
# Note: Fortunately, POSIXLY_CORRECT= works even without `export`, because
# use of `export` is not safe at this point.
# By contrast, a simple assignment cannot be tampered with.
POSIXLY_CORRECT=
# If defined, unset unset() and other functions that may shadow crucial commands.
# Note the \ prefix to ensure that aliases are bypassed.
\unset -f unset unalias read declare
# Remove all aliases.
# (Note that while alias expansion is off by default in scripts, it may
# have been turned on explicitly in a tampered-with environment.)
\unalias -a # Note: After this, \ to bypass aliases is no longer needed.
# Now it is safe to turn POSIX mode back off, so as to reenable all Bash
# features.
unset POSIXLY_CORRECT
# Now UNDEFINE ALL REMAINING FUNCTIONS:
# Note that we do this AFTER switching back from POSIX mode, because
# Bash in its default mode allows defining functions with nonstandard names
# such as `[` or `z?`, and such functions can also only be *unset* while
# in default mode.
# Also note that we needn't worry about keywords `while`, `do` and `done`
# being shadowed by functions, because the only way to invoke such functions
# (which you can only define with the nonstandard `function` keyword) would
# be with `\` (e.g., `\while`).
while read _ _ n; do unset -f "$n"; done < <(declare -F)
# IN THE REST OF THE SCRIPT:
# - It is now safe to call *builtins* as-is.
# - *External utilities* should be invoked:
# - by full path, if feasible
# - and/or, in the case of *standard utilities*, with
# command -p, which uses a minimal $PATH definition that only
# comprises the locations of standard utilities.
# - alternatively, as @jarno suggests, you can redefine your $PATH
# to contain standard locations only, after which you can invoke
# standard utilities by name only, as usual:
# PATH=$(command -p getconf PATH)
# Example command:
# Verify that `unset` now refers to the *builtin*:
type unset
测试命令:
假设上面的代码保存在当前目录下的文件script
中。
以下命令模拟了一个被篡改的环境,其中unset
被别名和函数所遮蔽,并且文件script
被源,导致它看到该函数,并在交互式源时扩展别名:
$ (unset() { echo hi; }; alias unset='echo here'; . ./script)
unset is a shell builtin
type unset
输出 unset 是一个shell内置命令
证明函数和别名都已被禁用,遮盖了内置命令 unset
。
POSIXLY_CORRECT=
确保在 Bash 中调用unset
时不使用 shell 函数。对于任何 POSIX 特殊内置实用程序也适用。但是这在 Zsh shell 中不起作用。 - jarnoPOSIXLY_CORRECT=
。例如,如果有一个哈希标记#!/bin/sh
,并且通过其名称运行脚本。请参见从bash手册页面链接的文档。 - jarno