在 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"带引号,以免您的命令在运行前被破坏。尝试 evaling 和 illcommando='printf "%s\n" " * "' 的值,带和不带引号,看看区别。 @TomášZato-ReinstateMonica 是的,它确实转发了命令的返回值。但是,它没有正确设置 bash 中的 "$PIPESTATUS[@]" 变量。但是,set -o pipefail 确实会正确地导致 eval 在命令包含通过管道传递给成功命令的失败命令时返回失败退出代码。 我试图做类似grep -E '$filter' unfiltered.txt &gt; 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 脚本中将字符串作为命令运行的主要内容,如果未能解决你的问题,请参考以下文章

在 Bash 中将文本文件作为命令运行

在批处理脚本中将变量字符串作为命令运行[关闭]

在bash中将包含空格的变量传递给命令[重复]

Makefile将变量传递给bash脚本

运行 bash 脚本的 docker 入口点得到“权限被拒绝”

shell脚本7---图形化shell