Linux 如何在shell脚本的变量中存储命令?
我想将稍后使用的命令存储在变量中(不是命令的输出,而是命令本身) 我有一个简单的脚本,如下所示:Linux 如何在shell脚本的变量中存储命令?,linux,bash,variables,command,Linux,Bash,Variables,Command,我想将稍后使用的命令存储在变量中(不是命令的输出,而是命令本身) 我有一个简单的脚本,如下所示: command="ls"; echo "Command: $command"; #Output is: Command: ls b=`$command`; echo $b; #Output is: public_html REV test... (command worked successfully) 然而,当我尝试一些更复杂的东西时,它失败了。例如,如果我 command="ls | gre
command="ls";
echo "Command: $command"; #Output is: Command: ls
b=`$command`;
echo $b; #Output is: public_html REV test... (command worked successfully)
然而,当我尝试一些更复杂的东西时,它失败了。例如,如果我
command="ls | grep -c '^'";
输出为:
Command: ls | grep -c '^'
ls: cannot access |: No such file or directory
ls: cannot access grep: No such file or directory
ls: cannot access '^': No such file or directory
知道如何将这样的命令(使用管道/多个命令)存储在变量中以供以后使用吗?即使您以后需要使用,也不需要将命令存储在变量中。只需按常规执行即可。如果存储在变量中,则需要某种
eval
语句或调用一些不必要的shell进程来“执行变量”。使用eval:
x="ls | wc"
eval "$x"
y=$(eval "$x")
echo "$y"
使用此方法,将立即计算命令并存储其返回值
stored_date=$(date)
echo $stored_date
# => Thu Jan 15 10:57:16 EST 2015
# (wait a few seconds)
echo $stored_date
# => Thu Jan 15 10:57:16 EST 2015
与backtick相同
stored_date=`date`
echo $stored_date
# => Thu Jan 15 11:02:19 EST 2015
# (wait a few seconds)
echo $stored_date
# => Thu Jan 15 11:02:19 EST 2015
在$(…)
中使用eval不会使其在以后进行计算
stored_date=$(eval "date")
echo $stored_date
# => Thu Jan 15 11:05:30 EST 2015
# (wait a few seconds)
echo $stored_date
# => Thu Jan 15 11:05:30 EST 2015
使用eval,在使用eval
时对其进行评估
stored_date="date" # < storing the command itself
echo $(eval "$stored_date")
# => Thu Jan 15 11:07:05 EST 2015
# (wait a few seconds)
echo $(eval "$stored_date")
# => Thu Jan 15 11:07:16 EST 2015
# ^^ Time changed
对于bash脚本来说,这很少有关系,但需要注意的是最后一点。小心使用eval
。仅评估您控制的字符串,从不评估来自不受信任用户或由不受信任用户输入生成的字符串
- 感谢@CharlesDuffy提醒我引用命令李>
- 不要使用
!它有引入任意代码执行的主要风险 -我试图将命令放入变量中,但复杂的情况总是失败。 将其放入一个数组中,并用双引号展开所有单词eval
,以避免“${arr[@]}”
因错误而拆分单词 并查看内部数组的内容。IFS
允许您在单独的索引中查看数组的内容以及每个命令参数。如果一个这样的参数包含空格,则在添加到数组时在内部加引号将防止它因分词而被拆分declare-p
并根据需要执行命令declare -p cmdArgs declare -a cmdArgs='([0]="date" [1]="+%H:%M:%S")'
(或)同时使用"${cmdArgs[@]}" 23:15:18
函数运行命令bash
并调用函数作为cmd() { date '+%H:%M:%S' }
POSIXcmd
没有数组,因此最接近的方法是在位置参数中建立元素列表。这里有一个POSIXsh
运行邮件程序的方法sh
注意,这种方法只能处理没有重定向的简单命令。它不能处理重定向、管道、for/while循环、if语句等 另一种常见的使用情况是使用多个标题字段和负载运行# POSIX sh # Usage: sendto subject address [address ...] sendto() { subject=$1 shift first=1 for addr; do if [ "$first" = 1 ]; then set --; first=0; fi set -- "$@" --recipient="$addr" done if [ "$first" = 1 ]; then echo "usage: sendto subject address [address ...]" return 1 fi MailTool --subject="$subject" "$@" }
。您始终可以像下面这样定义参数,并在扩展的数组内容上调用curl
curl
再比如,curlArgs=('-H' "keyheader: value" '-H' "2ndkeyheader: 2ndvalue") curl "${curlArgs[@]}"
现在定义了变量,使用数组存储命令参数payload='{}' hostURL='http://google.com' authToken='someToken' authHeader='Authorization:Bearer "'"$authToken"'"'
现在做一个适当的扩展curlCMD=(-X POST "$hostURL" --data "$payload" -H "Content-Type:application/json" -H "$authHeader")
curl "${curlCMD[@]}"
对于bash,按如下方式存储命令:command="ls | grep -c '^'"
echo $command | bash
按如下方式运行命令:$ cmd=ls $ $cmd # works file file2 test $ cmd='ls | grep file' $ $cmd # not works ls: cannot access '|': No such file or directory ls: cannot access 'grep': No such file or directory file $ bash -c $cmd # works file file2 test $ bash -c "$cmd" # also works file file2 $ bash <<< $cmd file file2 $ bash <<< "$cmd" file file2
command="ls | grep -c '^'"
echo $command | bash
$ cmd=ls $ $cmd # works file file2 test $ cmd='ls | grep file' $ $cmd # not works ls: cannot access '|': No such file or directory ls: cannot access 'grep': No such file or directory file $ bash -c $cmd # works file file2 test $ bash -c "$cmd" # also works file file2 $ bash <<< $cmd file file2 $ bash <<< "$cmd" file file2
我尝试了各种不同的方法:
输出:printexec() { printf -- "\033[1;37m$\033[0m" printf -- " %q" "$@" printf -- "\n" eval -- "$@" eval -- "$*" "$@" "$*" }
$ printexec echo -e "foo\n" bar $ echo -e foo\\n bar foon bar foon bar foo bar bash: echo -e foo\n bar: command not found
如您所见,只有第三个命令,
给出了正确的结果。使用以下命令注册订单时要小心:“$@”
这一次仍在执行中 甚至在被叫之前。 要检查并确认这一点,您可以执行以下操作:X=$(命令)
echo test; X=$(for ((c=0; c<=5; c++)); do sleep 2; done); echo note the 5 seconds elapsed
echo测试;
X=$(对于((c=0;c首先,有用于此的函数。但是如果您喜欢VAR,那么您的任务可以这样完成:command="ls | grep -c '^'"
echo $command | bash
$ cmd=ls $ $cmd # works file file2 test $ cmd='ls | grep file' $ $cmd # not works ls: cannot access '|': No such file or directory ls: cannot access 'grep': No such file or directory file $ bash -c $cmd # works file file2 test $ bash -c "$cmd" # also works file file2 $ bash <<< $cmd file file2 $ bash <<< "$cmd" file file2
我将存储的命令将取决于我发送的选项,因此我的程序中没有大量的条件语句,而是更容易存储我以后使用的命令。@Benjamin,然后至少将选项存储为变量,而不是命令。例如
$(…)现在建议使用,而不是var='*.txt';find.-name“$var”
.y=$(eval$x)backticks
是一种可接受的做法,前提是您信任变量的内容。如果您正在运行,比如说,eval
(甚至x=“ls$name | wc”
),则此代码是注入或权限提升漏洞的快速通道,如果该变量可以由权限较低的人设置。(例如,迭代x=“ls'$name'| wc”
中的所有子目录?您最好信任系统上的每个用户,不要将其称为/tmp
)。$'/tmp/evil-$(rm-rf$HOME)\'$(rm-rf$HOME)\“/”
是一个巨大的漏洞磁铁,如果没有关于意外解析行为风险的警告(即使没有恶意字符串,如@CharlesDuffy的示例),也不应该推荐它。例如,尝试eval
然后x='echo$(6*7)),
。您可能希望打印“42”,但它可能不会。你能解释为什么它不起作用吗?你能解释为什么我说“可能”?如果这些问题的答案对你来说不明显,你不应该触摸eval$x
@Student,试着事先运行eval
来记录命令的运行,这将更容易看到发生了什么。@Student我还建议你指出常见的错误(以及你不应该养成的坏习惯)。使用函数!请参阅本文:。这并不能解决命令中包含管道“|”的原始问题。@Nate,请注意,set-x
如果eval$stored_date
仅包含stored_date
,则可能足够了,但是date
更可靠。运行eval“$stored_date”
最后一个str=$'printf\*%s\\n\*”;eval“$str”
前后加引号,例如:)@Charlesduff谢谢,我忘了引用。我敢打赌,如果我费心运行它,我的linter会抱怨的。切记,这是一个@Student,如果原始字符串包含管道,那么该字符串需要经过bash解析器的不安全部分才能作为代码执行。在这种情况下,不要使用字符串,而是使用函数:“$str”
--之后您可以运行Command(){echo aaa | grep a;}
,或命令
,或类似操作。@Student,对;结果=$(命令)