在 Bash 脚本中将字符串作为命令运行
Posted
技术标签:
【中文标题】在 Bash 脚本中将字符串作为命令运行【英文标题】:Run a string as a command within a Bash script 【发布时间】:2011-01-22 05:54:23 【问题描述】:我有一个 Bash 脚本,它构建一个字符串以作为命令运行
脚本:
#! /bin/bash
matchdir="/home/joao/robocup/runner_workdir/matches/testmatch/"
teamAComm="`pwd`/a.sh"
teamBComm="`pwd`/b.sh"
include="`pwd`/server_official.conf"
serverbin='/usr/local/bin/rcssserver'
cd $matchdir
illcommando="$serverbin include='$include' server::team_l_start = '$teamAComm' server::team_r_start = '$teamBComm' CSVSaver::save='true' CSVSaver::filename = 'out.csv'"
echo "running: $illcommando"
# $illcommando > server-output.log 2> server-error.log
$illcommando
这似乎没有正确地向$serverbin
提供参数。
脚本输出:
running: /usr/local/bin/rcssserver include='/home/joao/robocup/runner_workdir/server_official.conf' server::team_l_start = '/home/joao/robocup/runner_workdir/a.sh' server::team_r_start = '/home/joao/robocup/runner_workdir/b.sh' CSVSaver::save='true' CSVSaver::filename = 'out.csv'
rcssserver-14.0.1
Copyright (C) 1995, 1996, 1997, 1998, 1999 Electrotechnical Laboratory.
2000 - 2009 RoboCup Soccer Simulator Maintenance Group.
Usage: /usr/local/bin/rcssserver [[-[-]]namespace::option=value]
[[-[-]][namespace::]help]
[[-[-]]include=file]
Options:
help
display generic help
include=file
parse the specified configuration file. Configuration files
have the same format as the command line options. The
configuration file specified will be parsed before all
subsequent options.
server::help
display detailed help for the "server" module
player::help
display detailed help for the "player" module
CSVSaver::help
display detailed help for the "CSVSaver" module
CSVSaver Options:
CSVSaver::save=<on|off|true|false|1|0|>
If save is on/true, then the saver will attempt to save the
results to the database. Otherwise it will do nothing.
current value: false
CSVSaver::filename='<STRING>'
The file to save the results to. If this file does not
exist it will be created. If the file does exist, the results
will be appended to the end.
current value: 'out.csv'
如果我只是粘贴命令/usr/local/bin/rcssserver include='/home/joao/robocup/runner_workdir/server_official.conf' server::team_l_start = '/home/joao/robocup/runner_workdir/a.sh' server::team_r_start = '/home/joao/robocup/runner_workdir/b.sh' CSVSaver::save='true' CSVSaver::filename = 'out.csv'
(在“runnning:”之后的输出中)它工作正常。
【问题讨论】:
因为mywiki.wooledge.org/BashFAQ/050 请注意,在某些情况下,您需要这样做:echo | whateverCommands
而不仅仅是 whateverCommands
(例如,我必须这样做:| tail -`echo | whateverCommands`
)
【参考方案1】:
我通常将命令放在括号 $(commandStr)
中,如果这对我发现 bash 调试模式没有帮助,请以 bash -x script
运行脚本
【讨论】:
我不确定 commandStr 指的是什么,但至少这对我不起作用。最好使用完整的工作示例。 @RobinManoli 为你提高了清晰度。 commandStr="ls -l" $(echo commandStr) #should work【参考方案2】:不要把你的命令放在变量中,直接运行它
matchdir="/home/joao/robocup/runner_workdir/matches/testmatch/"
PWD=$(pwd)
teamAComm="$PWD/a.sh"
teamBComm="$PWD/b.sh"
include="$PWD/server_official.conf"
serverbin='/usr/local/bin/rcssserver'
cd $matchdir
$serverbin include=$include server::team_l_start = $teamAComm server::team_r_start=$teamBComm CSVSaver::save='true' CSVSaver::filename = 'out.csv'
【讨论】:
就是这样做的。但是在我有变量应该作为单个参数的地方我做了"$arg"
。例如:server::team_l_start = "$teamAComm"
对于很多调试任务,最好将命令放在一个字符串中。为我省去了很多麻烦。【参考方案3】:
你可以使用eval
来执行一个字符串:
eval $illcommando
【讨论】:
eval是否传递命令返回值(返回值,不是字符串输出)?eval
在所有编程语言中都是一个邪恶的命令,因此请谨慎使用。
eval "$illcommando"
,带引号,以免您的命令在运行前被破坏。尝试 eval
ing 和 illcommando='printf "%s\n" " * "'
的值,带和不带引号,看看区别。
@TomášZato-ReinstateMonica 是的,它确实转发了命令的返回值。但是,它没有正确设置 bash 中的 "$PIPESTATUS[@]"
变量。但是,set -o pipefail
确实会正确地导致 eval
在命令包含通过管道传递给成功命令的失败命令时返回失败退出代码。
我试图做类似grep -E '$filter' unfiltered.txt > filtered.txt
的事情,我不知道为什么它在命令行上工作以及为什么计算值在 bash 脚本中不起作用。您的回答保存了我的脚本。我将在这里添加一些很好的文档示例,我用来更好地理解 eval 的工作原理。 linuxhint.com/bash_eval_command【参考方案4】:
./me 强制转换 raise_dead()
我一直在寻找这样的东西,但我还需要重用相同的字符串减去两个参数,所以我最终得到了类似的东西:
my_exe ()
mysql -sN -e "select $1 from heat.stack where heat.stack.name=\"$2\";"
这是我用来监控 openstack 热堆栈创建的东西。在这种情况下,我期望两个条件,一个操作“CREATE”和一个名为“Somestack”的堆栈上的状态“COMPLETE”
要获取这些变量,我可以执行以下操作:
ACTION=$(my_exe action Somestack)
STATUS=$(my_exe status Somestack)
if [[ "$ACTION" == "CREATE" ]] && [[ "$STATUS" == "COMPLETE" ]]
...
【讨论】:
【参考方案5】:your_command_string="..."
output=$(eval "$your_command_string")
echo "$output"
【讨论】:
看起来很有趣,但对我不起作用。$your_command_string
不会被执行。有什么问题?
为我工作。不知道放在哪里,但请注意,不要在=
之前添加空格,例如your_command_string ="..."
【参考方案6】:
这是我的 gradle 构建脚本,它执行存储在 heredocs 中的字符串:
current_directory=$( realpath "." )
GENERATED=$current_directory/"GENERATED"
build_gradle=$( realpath build.gradle )
## touch because .gitignore ignores this folder:
touch $GENERATED
COPY_BUILD_FILE=$( cat <<COPY_BUILD_FILE_HEREDOC
cp
$build_gradle
$GENERATED/build.gradle
COPY_BUILD_FILE_HEREDOC
)
$COPY_BUILD_FILE
GRADLE_COMMAND=$( cat <<GRADLE_COMMAND_HEREDOC
gradle run
--build-file
$GENERATED/build.gradle
--gradle-user-home
$GENERATED
--no-daemon
GRADLE_COMMAND_HEREDOC
)
$GRADLE_COMMAND
单独的“)”有点丑陋。但我不知道如何解决这个审美问题。
【讨论】:
【参考方案7】:要查看脚本正在执行的所有命令,请将 -x
标志添加到您的 shabang 行,然后正常执行命令:
#! /bin/bash -x
matchdir="/home/joao/robocup/runner_workdir/matches/testmatch/"
teamAComm="`pwd`/a.sh"
teamBComm="`pwd`/b.sh"
include="`pwd`/server_official.conf"
serverbin='/usr/local/bin/rcssserver'
cd $matchdir
$serverbin include="$include" server::team_l_start="$teamAComm" server::team_r_start="$teamBComm" CSVSaver::save='true' CSVSaver::filename='out.csv'
如果您有时想忽略调试输出,请将stderr
重定向到某个地方。
【讨论】:
【参考方案8】:对我来说echo XYZ_20200824.zip | grep -Eo '[[:digit:]]4[[:digit:]]2[[:digit:]]2'
工作正常,但无法将命令输出存储到变量中。
我有同样的问题,我试过eval
,但没有输出。
这是我的问题的答案:
cmd=$(echo XYZ_20200824.zip | grep -Eo '[[:digit:]]4[[:digit:]]2[[:digit:]]2')
echo $cmd
我的输出现在是20200824
【讨论】:
以上是关于在 Bash 脚本中将字符串作为命令运行的主要内容,如果未能解决你的问题,请参考以下文章