Führen Sie eine Zeichenfolge als Befehl in einem Bash-Skript aus

151

Ich habe ein Bash-Skript, das eine Zeichenfolge erstellt, die als Befehl ausgeführt werden soll

Skript:

#! /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

das scheint die Argumente nicht richtig zu liefern $serverbin.

Skriptausgabe:

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'

Wenn ich nur den Befehl /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'einfüge (in der Ausgabe nach "runnning:"), funktioniert es einwandfrei.

João Portela
quelle
Beachten Sie, dass in einigen Fällen müssen Sie tun: echo | whateverCommandsStatt nur von whateverCommands(zum Beispiel, ich hatte es , wie dies zu tun: | tail -`echo | whateverCommands`)
Andrew

Antworten:

277

Sie können evaleine Zeichenfolge ausführen:

eval $illcommando
Arne Burmeister
quelle
2
Gibt eval den Befehlsrückgabewert weiter ( Rückgabewert , keine Zeichenfolgenausgabe)?
Tomáš Zato - Wiedereinsetzung Monica
3
evalist ein böser Befehl in allen Programmiersprachen, verwenden Sie ihn daher mit Vorsicht.
Krishnadas PC
1
eval "$illcommando", Mit den Anführungszeichen , nicht zu Ihrem Befehl , bevor es läuft verstümmelt hat. Versuchen evalSie es mit einem Wert von illcommando='printf "%s\n" " * "'mit und ohne Anführungszeichen, um den Unterschied zu erkennen.
Charles Duffy
@ TomášZato-ReinstateMonica Ja, der Rückgabewert des Befehls wird weitergeleitet. Die "${PIPESTATUS[@]}"Variable in bash wird jedoch NICHT richtig eingestellt. Allerdings set -o pipefailführt nicht ordnungsgemäß evaleinen Fehler Exit - Code zurück , wenn der Befehl Befehl enthält andernfalls zu einem erfolgreichen Befehl geleitet.
Cameron Hudson
Ich habe versucht, so etwas wie zu tun grep -E '$filter' unfiltered.txt > filtered.txt. Ich hatte keine Ahnung, warum es in der Befehlszeile funktioniert und warum es mit berechneten Werten im Bash-Skript nicht funktioniert. Ihre Antwort hat mein Skript gespeichert. Ich werde hier auch einige schöne dokumentierte Beispiele hinzufügen, die ich verwendet habe, um besser zu verstehen, wie eval funktioniert. linuxhint.com/bash_eval_command
student0495
28

Normalerweise setze ich Befehle in Klammern $(commandStr). Wenn dies nicht dazu beiträgt , dass der Bash-Debug-Modus großartig ist, führen Sie das Skript als ausbash -x script

Ola
quelle
4
Ich bin nicht sicher, worauf sich commandStr bezieht, aber zumindest hat dies bei mir nicht funktioniert. Es ist besser, wenn Sie vollständige Arbeitsbeispiele verwenden.
Robin Manoli
@RobinManoli Verbesserte die Klarheit für dich.
Andrew
18
your_command_string="..."
output=$(eval "$your_command_string")
echo "$output"
Takman
quelle
10

Fügen Sie Ihre Befehle nicht in Variablen ein, sondern führen Sie sie einfach aus

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'
Ghostdog74
quelle
1
tat genau das. aber wo ich Variablen hatte, die nur als ein einziges Argument gehen sollten, tat ich "${arg}". Beispiel: server :: team_l_start = "$ {teamAComm}"
João Portela
1

./me Casts Raise_Dead ()

Ich habe nach so etwas gesucht, aber ich musste auch denselben String minus zwei Parameter wiederverwenden, damit ich am Ende so etwas wie:

my_exe ()
{
    mysql -sN -e "select $1 from heat.stack where heat.stack.name=\"$2\";"
}

Dies ist etwas, das ich verwende, um die Erstellung von Openstack-Heatstacks zu überwachen. In diesem Fall erwarte ich zwei Bedingungen, eine Aktion 'CREATE' und einen Status 'COMPLETE' auf einem Stapel mit dem Namen "Somestack".

Um diese Variablen zu erhalten, kann ich Folgendes tun:

ACTION=$(my_exe action Somestack)
STATUS=$(my_exe status Somestack)
if [[ "$ACTION" == "CREATE" ]] && [[ "$STATUS" == "COMPLETE" ]]
...
cmyster
quelle
0

Hier ist mein Gradle-Build-Skript, das in Heredocs gespeicherte Zeichenfolgen ausführt :

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

Die einsamen ")" sind irgendwie hässlich. Aber ich habe keine Ahnung, wie ich diesen ästhetischen Aspekt beheben kann.

JMI MADISON
quelle
0

Um alle Befehle -xanzuzeigen , die vom Skript ausgeführt werden, fügen Sie das Flag zu Ihrer Shabang-Zeile hinzu und führen Sie den Befehl normal aus:

#! /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'

Wenn Sie dann manchmal die Debug-Ausgabe ignorieren möchten, leiten Sie stderrirgendwo um.

Yigal
quelle