我的意思是我想使用不是shell函数本身的command
。如果我能做到这一点,我可以通过运行
#!/bin/sh
{ \unset -f unalias command [; \unalias unset command [ } 2>/dev/null;
# make zsh find *builtins* with `command` too:
[ -n "$ZSH_VERSION" ] && options[POSIX_BUILTINS]=on
是纯粹的
\unset
如果我使用的是Debian Almquist shell(破折号),我认为我可以依赖unset
是纯粹的。至少我无法在dash
中定义名为bash
的shell函数。在zsh
或unset() { echo fake unset; }
中,我可以定义\unset -f unset
,之后我无法取消设置功能:bash
输出&#34;假未设置&#34;。< / p>
与此相关,在export -f <function name>
脚本中,可以通过bash
导出函数,以便可以在脚本调用的dash
脚本中使用它。但是,这在dash
脚本中不起作用。我想知道,如果我要使用Create Procedure [dbo].[Sp_User]
(
@Id int=null,
@FullName varchar(50)=null,
@Password varchar(50)=null,
@Address varchar(100)=null,
@Email varchar(50)=null,
@Imgurl varchar(50)=null,
@Activity varchar(50)=null
)
As Begin
if(@Activity='Add')
insert into registration
(FullName,[Password],[Address],Email,Imgurl)
values
(@FullName,@Password,@Address,@Email,@Imgurl)
if(@Activity = 'All')
select top 1 FullName,Email,Password,imgurl from registration order by Id desc
End
,我是否必须担心在我编写的脚本文件之外将命令定义为shell函数?其他POSIX兼容的shell怎么样?
答案 0 :(得分:8)
注意:除非另有说明,否则以下内容适用于所有与POSIX兼容的主要shell:bash
,dash
,ksh
和zsh
。 (dash
,Debian Almquist Shell,是基于Debian的Linux发行版(如Ubuntu)的默认shell(sh
)。
unset
具有原始含义 - a builtin that can undefine shell functions with its -f
option - 是键,用于确保任何其他shell关键字,命令或内置文件具有其原始内容意强>
unset
开始,您可以确保未经修改的shopt
和/或command
,它们可以一起用于绕过或取消定义可能影子的任何别名或shell函数shell关键字,内置函数和外部实用程序。command
可用于绕过它们,包括那些可能已在外部定义的 >你的代码,通过环境; bash
支持的导出功能才是这些机制的一个;不同的壳有不同的壳可能支持几个 - 见下文。 在POSIX兼容模式下,只有dash
,ksh
和bash
才能保证unset
不是&#39 ; t重新定义:
dash
和ksh
是安全的,因为他们不允许定义名为{{1}的函数 },正如您所发现的那样,任何别名形式都可以通过调用unset
来绕过。
\unset
,在POSIX兼容模式时,允许您定义名为bash
的函数,但忽略当你调用unset
时,它总是会执行内置的,就像你后来发现的一样。
可悲的是,据我所知,在 unset
- 以及unset
的默认模式中 - 有否保证zsh
本身没有被重新定义的方法,并且可能存在其他类似POSIX的shell。
bash
(引用名称的任何部分)将绕过别名重新定义,但不会绕过功能重新定义 - 并撤消您需要原始的unset
本身:赶上22。因此,无法控制执行环境,您无法编写完全免于篡改的shell脚本, 除非您知道您的代码将由\unset
,unset
或dash
执行(具有适当的解决方法)。
如果您愿意假设ksh
未被篡改,最强大的方法是:
使用bash
确保unset
和\unset -f
未被修改(未被shell函数遮蔽:unalias
)
command
在\unset -f unalias command
中有效,typeset -f
和bash
,但dash
appears to have no mechanism at all),以便始终无法定义所有功能。使用ksh
删除所有别名。
然后使用zsh
调用所有,但您定义的函数除外。在调用外部实用程序时,尽可能使用显式路径,和/或在标准实用程序的情况下,使用\unalias -a
,它使用限制在标准位置的最小command [-p]
定义(运行command -p
来查看该定义)。
其他信息:
根据POSIX,引用命令名称的任何部分(例如$PATH
)会绕过任何别名表单或关键字表单(该名称中的保留字在POSIX和command -p getconf PATH
用语中 - 但不 shell 函数。
根据POSIX,\unset
取消定义所有别名。没有等效的POSIX兼容命令可以取消定义所有函数。
zsh
版本不支持unalias -a
;但至少zsh
,他们确实如此。内置-a
可用于绕过v5.0.8
,command
和bash
中的关键字,别名,功能 - 换句话说:{{1} }只执行 builtins 和外部实用程序。相比之下,dash
默认也绕过 builtins ;要使ksh
执行内置函数,请使用command
。
以下内容可用于在所有shell中执行名为zsh
的外部实用程序:
zsh
请注意,尽管options[POSIX_BUILTINS]=on
不是POSIX实用程序,但它在现代类Unix平台上广泛使用。
命令表格的优先顺序:
<name>
,"$(command which <name>)" ...
:别名&gt; shell关键字&gt; shell函数&gt; builtin&gt;外部效用which
,bash
:shell关键字&gt;别名&gt; shell函数&gt; builtin&gt;外部效用zsh
和ksh
中,别名可以覆盖shell关键字,而dash
和bash
则不能覆盖。 zsh
,ksh
和dash
- 但不是bash
- 所有允许非标准功能签名ksh
作为替代与POSIX兼容的zsh
表单。
dash
语法是以下先决条件:
function <name> { ...
; <name>() { ...
。function
的情况下,使用<name>
语法还意味着<name>
语句创建本地变量。)\while
,ksh
和function
还会阻止特殊内置命名函数(例如{ {1}},typeset
,dash
,ksh
);可以找到POSIX定义的特殊内置列表here; bash
和unset
添加了一些无法重新定义的内容(例如,break
中的set
; shift
中的dash
和ksh
但是,两个shell都有额外的非特殊内置,可以重新定义(例如,local
)。dash
的情况下,无论是否使用typeset
语法,上述规则都适用。代码范围内环境shell函数的潜在来源:
注意:防范这些的最简单方法是使用(未修改的)unalias
内置(在ksh
中使用type
,以防止绕过内置函数)无论何时你想调用内置或外部实用程序。
POSIX要求由环境变量ksh
中的绝对路径指定的脚本为交互式 shell 源(有一些限制 - 请参阅{ {3}}); function
和command
始终尊重这一点,而zsh
仅在options[POSIX_BUILTINS]=on
或v4.2 +中使用ENV
时才会这样做;相比之下,ksh
从不尊重这个变量。
dash
调用您的脚本来强制交互式实例。 bash
有 2 机制:
sh
或--posix
导出单个函数(其他shell仅支持导出变量)zsh
中启动非交互式 shell时要发送的脚本的完整路径。 sh -i
通过可选的bash
环境变量支持自动加载:包含位于export -f
中指定的任何目录中的函数定义的文件是隐式自动加载。
declare -fx
也支持BASH_ENV
,但自动加载功能需要显式 ksh
语句,因此除非您特别要求给定函数要自动加载的名称,不会将任何函数添加到shell中。) FPATH
支持通过其FPATH
和zsh
初始化文件为任何 FPATH
实例(无论是否具有交互性)获取脚本
(autoload <name>
似乎不支持通过环境定义功能的任何机制。)
zsh
的解决方法:确保zsh
具有原始含义: 如果你知道/etc/zshenv
将执行你的脚本,这种解决方法是安全的,遗憾的是,这本身不能保证。
此外,因为它修改了shell环境(删除了别名和函数),所以它不适合设计为源的脚本。
如上所述,在Bash的POSIX兼容模式下运行代码通常不合适,但您可以暂时激活它以确保{{1} }没有被函数遮蔽:
~/.zhsenv
测试命令:
假设上面的代码已保存到当前目录中的文件dash
。
以下命令模拟篡改环境,其中bash
被别名和函数遮蔽,文件unset
来源,导致其看到函数和交互式源代码,也可以扩展别名:
bash
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
的函数和别名都已停用。
答案 1 :(得分:1)
command
$ var="FOO"
$ unset() { echo nope; }
$ echo "${var}"
FOO
$ unset var
nope
$ echo "${var}"
FOO
$ command unset var
$ echo "${var}"
<nothing!>
如果您处于有人创建command() { :; }
功能的恶劣环境中,这无济于事。但如果你处于敌对的环境中,你已经输了;)。
在将功能导出到环境中时,这是一个特定于bash的扩展,你不应该真的依赖它。 POSIX shell(如破折号)不支持设计。
答案 2 :(得分:1)
这就是我知道可以做些什么......
#!/bin/bash --posix # if e.g. BASH_FUNC_unset() env variable is set, script execution cannot # get this far (provided that it is run as is, not as `bash script ...`) unset -f builtin command declare ... saved_IFS=$IFS; readonly saved_IFS # remove all functions (shell builtin declare executed in subshell) IFS=$'\n'; for f in `declare -Fx`; do unset -f ${f##* }; done; IFS=$saved_IFS