简体   繁体   English

BASH:执行存储在数组中的命令

[英]BASH: Execute commands stored in array

I am trying to execute a shell script like below我正在尝试执行如下所示的 shell 脚本

cmds=('uptime' 'free -m' 'nproc')
for cmd in ${cmds[@]};
do
echo $($cmd)
done

Execution is breaking when it comes to free -m execution because of space.由于空间的原因,执行在free -m执行方面正在中断。

vagrant@vagrant-ubuntu-trusty-64:~$ bash for_my_script.sh
 03:42:50 up 56 min,  1 user,  load average: 0.00, 0.00, 0.00
              total        used        free      shared  buff/cache   available
Mem:         499928      108516       43204        1844      348208      366140
Swap:             0           0           0
for_my_script.sh: line 5: -m: command not found

1
vagrant@vagrant-ubuntu-trusty-64:~$

I tried iterating with for by storing commands in variable我尝试通过将命令存储在变量中来迭代 for

vagrant@vagrant-ubuntu-trusty-64:~$ cmds="uptime,free -m"
vagrant@vagrant-ubuntu-trusty-64:~$ for cmd in "${cmds//,/ }"; do echo "$($cmd)"; done
uptime: invalid option -- 'm'
vagrant@vagrant-ubuntu-trusty-64:~$ cmds="uptime,'free -m'"
vagrant@vagrant-ubuntu-trusty-64:~$ for cmd in "${cmds//,/ }"; do echo "$($cmd)"; done
uptime: invalid option -- 'm'

With no success.没有成功。

is touching IFS is the only way for this type of problem?接触IFS是解决此类问题的唯一方法吗? any inputs are much appreciated.任何输入都非常感谢。

Thank you.谢谢你。

The accepted answer still involves unquoted strings , which are discouraged and error-prone.接受的答案仍然涉及不带引号的字符串,这是不鼓励和容易出错的。 You could use eval as @Fravadona suggests, but eval is also hard to work with properly/safely .可以按照@Fravadona 的建议使用eval ,但eval很难正确/安全地使用

Instead, consider creating functions to wrap the commands you want to run;相反,请考虑创建函数来包装要运行的命令; then you don't need to deal with nested arguments within strings.那么你不需要处理字符串中的嵌套参数。 Functions also makes it easy to compose more complex behavior (pipelines, conditionals, etc.) without complicating the execution loop.函数还可以轻松组合更复杂的行为(管道、条件等),而不会使执行循环复杂化。 Something like:就像是:

do_free() { free -m; }

cmds=(uptime do_free nproc)
for cmd in "${cmds[@]}"; do
  "$cmd"  # notice that you don't need echo $("$cmd"); it's generally redundant
done

You could create wrappers for uptime and nproc too for consistency, but it's not necessary as long as you don't need to pass any arguments.您可以为uptimenproc创建包装器以保持一致性,但只要您不需要传递任何参数,就没有必要。

For a more complete example of what I'm suggesting see this heartbeat script and the COMMANDS array in particular.有关我建议的更完整示例,请参阅此心跳脚本和特别是COMMANDS数组。

You have to change your code from:您必须从以下位置更改代码:

cmds=('uptime' 'free -m' 'nproc')
for cmd in ${cmds[@]};
do
echo $(${cmd})
done

into进入

cmds=('uptime' 'free -m' 'nproc')
for cmd in "${cmds[@]}";
do
echo $(${cmd})
done

You missed double quotes around ${cmds[@]} .您错过了${cmds[@]}周围的双引号。

WARNING WITH THE ACCEPTED ANSWER接受答案的警告

In this specific case the right way IS to use eval , so your script should be:在这种特定情况下,正确的方法使用eval ,因此您的脚本应该是:

cmds=('uptime' 'free -m' 'nproc')
for cmd in "${cmds[@]}"
do
    eval "$cmd"
done

note: That is, if you store each command the same way that you would type them in the terminal.注意:也就是说,如果您以与在终端中键入命令相同的方式存储每个命令。


Let's see a few examples:让我们看几个例子:

# cmd='echo "a     b"'
# eval "$cmd"
a     b
# $cmd
"a b"
# echo $(${cmd})
"a b"
#
# cmd='echo a; echo b'
# eval "$cmd"
a
b
# $cmd
a; echo b
# echo $(${cmd})
a; echo b
#
# cmd='echo;'
# eval "$cmd"

# $cmd
bash: echo;: command not found...
# echo $(${cmd})
bash: echo;: command not found...

#

AL: eval is evil when you don't know how and when to use it AL:当你不知道如何以及何时使用它时, eval是邪恶的

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM