eval
命令可以做什么?为什么有用?它是bash中的某种内置函数吗?没有它的man
页面。.#1 楼
eval
是POSIX的一部分。它的接口可以是内置的shell。在“ POSIX程序员手册”中进行了介绍:http://www.unix.com/man-page/posix/1posix/eval/
eval - construct command by concatenating arguments
它将接受一个参数并构造一个命令,该命令将由Shell执行。这是联机帮助页的示例:
1) foo=10 x=foo
2) y='$'$x
3) echo $y
4) $foo
5) eval y='$'$x
6) echo $y
7) 10
在第一行中,您定义
$foo
和'10'
的值分别为$x
和'foo'
。 现在定义
$y
,它由字符串'$foo'
组成。必须使用'$'
对美元符号进行转义。
要检查结果,请输入
echo $y
。它将首先将'$foo'
评估为字符串eval
。现在我们有了语句$x
,它将被评估为'foo'
。y=$foo
的结果现在是值y=10
。 Perl和JavaScript。有关更多示例,请查看perldoc eval:http://perldoc.perl.org/functions/eval.html
评论
用shell术语来说,eval是内置的,而不是函数。在实践中,内置程序的行为很像没有语言定义的函数,但没有那么定义(如果扭曲得足以定义一个名为eval的函数,这很明显)。
–吉尔斯'所以-不再是邪恶的'
11-10-23在1:17
thx,固定为:-)
– echox
2011-10-25 14:14
eval和backticks`有什么区别?
–JohnyTex
15年3月20日在9:16
反引号是执行另一个整个shell的简写,这意味着您将在脚本中运行另一个子bash / sh进程。
–亚伦·R。
15-10-19在15:38
为什么echo $ y(stage 3)带回foo(10)而不是$ foo? (即只是foo的值而不是字符串$ + foo的值)?
–user149572
16 Dec 25 '17:00
#2 楼
是的,eval
是bash内部命令,因此在bash
手册页中进行了介绍。eval [arg ...]
The args are read and concatenated together into a single com-
mand. This command is then read and executed by the shell, and
its exit status is returned as the value of eval. If there are
no args, or only null arguments, eval returns 0.
通常将其与Command Substitution结合使用。如果没有显式的
eval
,外壳程序将尝试执行命令替换的结果,而不是对其求值。假设您要编写等效于
VAR=value; echo $VAR
的代码。请注意,外壳处理echo VAR=value
的方式有所不同:andcoz@...:~> $( echo VAR=value )
bash: VAR=value: command not found
andcoz@...:~> echo $VAR
<empty line>
外壳试图将
echo
和VAR=value
作为两个单独的命令执行。它引发有关第二个字符串的错误。赋值仍然无效。 。最后但并非最不重要的一点是,
echo
可能是非常危险的命令。必须仔细检查对VAR=value
命令的任何输入,以避免安全问题。#3 楼
eval
没有手册页,因为它不是单独的外部命令,而是内置的shell,这意味着该命令是shell内部的且仅由shell知道(bash
)。 bash
手册页的相关部分显示:eval [arg ...]
The args are read and concatenated together into a single command.
This command is then read and executed by the shell, and its exit
status is returned as the value of eval. If there are no args, or only
null arguments, eval returns 0
此外,
help eval
的输出是: br /> eval
是一个功能强大的命令,如果您打算使用它,则应格外小心,以免随之而来的安全隐患。 #4 楼
eval语句告诉外壳程序将eval的参数作为命令并通过命令行运行它们。在以下情况下很有用:在脚本中,如果要将命令定义为变量,以后又想使用该命令,则应使用eval:
/home/user1 > a="ls | more"
/home/user1 > $a
bash: command not found: ls | more
/home/user1 > # Above command didn't work as ls tried to list file with name pipe (|) and more. But these files are not there
/home/user1 > eval $a
file.txt
mailids
remote_cmd.sh
sample.txt
tmp
/home/user1 >
评论
您的示例的第4行中的注释是错误的:应该为“以上命令不起作用,因为bash试图找到名为ls | more的命令。换句话说:单个命令名称由9个字符组成,包括空格和管道符号。
–cfi
2015年10月16日13:41
我得到他报告的完全相同的行为。 bash --version == GNU bash版本3.2.57(1)-发行版(x86_64-apple-darwin18)
–亚历山大·伯德(Alexander Bird)
19年4月26日在17:24
#5 楼
什么是eval?
eval是一个Shell命令,通常实现为内置命令。
在POSIX中,它被列为“ 2.14。“ eval”条目中的“特殊的内置实用程序”。
内置的含义是:
术语“内置”表示外壳程序可以执行
它有什么作用?
简单来说:使输入行被解析两次。 br />
它是如何做到的?
shell遵循一系列步骤来“处理”一行。
您可以看一下这张图,并意识到eval是唯一返回到左侧第1步的行。
从POSIX描述:
2.1 Shell简介
Shell读取其输入....
Shell将输入分解为令牌:单词和运算符
Shell将输入解析为简单的复合命令。
Shell(分别)执行各种扩展操作...
Shell执行重定向,并从参数列表中删除重定向运算符及其操作数。
Shell执行函数,内置,可执行文件或脚本...
Shell可以选择等待命令完成并收集退出状态。
在步骤6中将执行内置程序。
在步骤6中,eval导致将已处理的行发送回步骤1。
这是执行顺序返回的唯一条件。
这就是为什么我说:使用eval将输入行解析两次。
解析两次的效果。
第一个。
最重要的影响要理解。引用是一行第一次受到上述七个shell步骤的结果。在第4步(扩展)中,还有一系列执行所有扩展的步骤,其中最后一个是引号删除:
引号删除应始终在最后执行。
因此,总是只有一个级别的引号被删除。
第二个。
作为第一个效果的结果,该行的其他/不同部分将暴露给Shell解析以及所有其他步骤。
示例。
间接。
可以执行间接扩展:
a=b b=c ; eval echo $$a ### shall produce "c"
为什么?
>因为在第一个循环上,第一个
$
被引用。因此,shell扩展将忽略它。
下一个名称为a的
$
被扩展为产生“ b”。 />然后,删除一级报价,使第一个$
不再被引用。第一个循环的结尾。 shell。
然后扩展为“ c”
,并将其作为
$b
的自变量。要“查看”在第一个循环中将产生什么eval(即ev再度减少),请使用echo。或任何清楚显示参数的命令/脚本/程序:
echo
用回显“看到”正在发生的事情:
$ a=b b=c
$ eval echo $$a;
c
也可以显示全部在以下示例中,一行的“部分”为:
$ echo echo $$a
echo $b
在此示例中,只有一个回声和一个变量,但请记住它可以帮助评估更复杂的情况。
更正。
必须指出:代码中有错误上面,您能看到吗?。
简单:缺少一些引号。
如何?你可能会问。很简单,让我们更改变量(而不是代码):
$ printf '<%s> ' echo $$a
<echo> <$b>
查看缺少的空格?
那是因为
$ a=b b="hi jk"
$ eval echo $$a
hi jk
内部的值被外壳分割了。如果那不能使您信服,请尝试以下操作:
$b
为什么?
缺少引号。为了使其正常工作(添加内部
$ a=b b="hi * jk"
$ eval echo $$a ### warning this will expand to the list
### of all files in the present directory.
和外部"$a"
引号)。请尝试以下操作(非常安全):
\"
关于手册:
没有手册页。.
不,没有独立的手册页。
搜索带有
$ a=b b="hi * jk"
$ eval echo \" $"$a" \"
hi * jk
甚至man -f eval
的手册不会显示任何条目。它包含在
apropos eval
中。和任何内置的一样。搜索“ SHELL BUILTIN COMMANDS”,然后搜索“ eval”。
获得帮助的更简单方法是:
在bash中,您可以请执行
man bash
来查看内置帮助。为什么将eval称为邪恶?
,因为它是动态地将文本绑定到代码。
换句话说:它将参数列表(和/或此类参数的扩展)转换为执行的行。如果由于某种原因攻击者设置了一个参数,则您将执行攻击者代码。
或更简单的方法是,通过eval告诉谁定义了一个或几个参数的值:
来吧,坐在这里键入任何命令行,我将尽力执行。
危险吗?每个人都应该清楚它是什么。
eval的安全规则应为:
仅对您赋予其值的变量执行eval。
在此处阅读更多详细信息。
#6 楼
eval
是大多数解释语言(TCL
,python
,ruby
...)的功能,不仅限于shell。它用于动态评估代码。在shell中,它是作为shell内置命令实现的。
基本上,
eval
以字符串作为参数并评估/解释其中的代码。 。在shell中,eval
可以接受多个参数,但是eval
只是将它们连接起来以形成要评估的字符串。它非常强大,因为您可以动态地构建代码并运行它,而您不能做像C这样的编译语言。
例如:
varname= varvalue=
eval "$varname=$varvalue" # evaluate a string like "foo=$varvalue"
# which in Bourne-like shell language
# is a variable assignment.
例如,如果上面的
eval
是
,则evil-command; var
将最终评估eval
Shell代码,然后运行该evil-command; var=$varvalue
。/>
evil-command
的弊端常常被夸大了。好,很危险,但至少我们知道这很危险。
很多其他命令如果未清除,将在其参数中评估shell代码,例如(取决于shell),
eval
aka [
,test
,export
,GNU printf
,sed
和当然awk
/ sh
/ bash
以及所有解释器... 示例(此处使用
perl
作为uname
和evil-command
作为外部提供的未消毒数据):$ a='$(uname>&2)' sh -c 'eval "echo $a"'
Linux
$ a='x[0$(uname>&2)]' mksh -c 'export "$a=$b"'
Linux
$ a='x[0$(uname>&2)]' ksh93 -c 'printf "%d\n" "$a"'
Linux
0
$ a='x[0$(uname>&2)]' ksh93 -c '[ "$a" -gt 0 ]'
Linux
$ a=$'bar/g;e uname>&2\n;s//'; echo foo | sed "s/foo/$a/g"
Linux
bar
$ a='";system("uname");"'; awk "BEGIN{print \"$a\"}"
Linux
$ a=';uname'; sh -c "echo $a"
Linux
那些
$a
,sed
...命令可能被认为更危险,因为虽然export
很明显会导致将eval "$var"
的内容评估为shell代码,但对于$var
或sed "s/foo/$var/"
或export "$var=value"
来说却不是那么明显。危险性相同,但是其他命令中都隐藏了它。评论
@BinaryZebra,像eval一样将sed传递给变量中包含的字符串,并且对于这两者,该字符串的内容最终都将作为shell代码进行评估,因此sed与eval一样危险,这就是我要说的。 sed被传递一个包含uname的字符串(到目前为止尚未执行uname),并且通过调用sed,uname命令最终被执行。喜欢评估。在sed的s / foo / $ a / g中,您没有将未经消毒的数据传递给sed,这不是我们在这里所说的。
–StéphaneChazelas
2015年12月19日在20:52
好答案,真的为我澄清了。我们可以使用eval动态分配值和变量名!
–information_interchange
20 Aug 10 '18:57
#7 楼
该示例可能会引起一些启发:#!/bin/bash
VAR1=25
VAR2='$VAR1'
VAR3='$VAR2'
echo "$VAR3"
eval echo "$VAR3"
eval eval echo "$VAR3"
上面脚本的输出:
$VAR2
$VAR1
25
评论
感谢您的贡献,但是,尽管如此,我们仍然很有趣,因此我们并没有兴趣编写一系列(略有不同)使用eval的示例列表。您是否相信现有答案未涵盖eval功能的一些基本,关键方面?如果是这样,请对其进行解释,并使用示例来说明您的解释。请不要回应发票;编辑您的答案,使其更清晰,更完整。
–斯科特
18-09-14在16:43
#8 楼
我对eval
的经验可以将命令的字符串输出转换为变量,这个示例来自另一个问题。eval $(ffprobe -v error -of flat=s=_ -select_streams v:0 -show_entries stream=height,width ${FILE})
当我直接将其输入到我得到的终端上时
streams_stream_0_width=1280
streams_stream_0_height=720
那个答案将每个变量存储到新变量中以在脚本中使用。
IN_WIDTH=${streams_stream_0_width}
在处理主命令(例如,获取文件属性或远程服务器状态)之前,可以从另一个命令返回中受益,这可能很有用。 >
评论
使用type命令了解命令的类型。 (在这种情况下,键入eval)“ eval是内置的shell”
帮助评估从您的shell获取“ man”页面
eval是bash内置的,并记录在bash的手册页中。因此,只需键入“ man bash”并搜索相应的部分eval。这也适用于其他bash-builtins。