Запустите строку как команду в скрипте Bash

152

У меня есть сценарий 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
tripleee
Обратите внимание , что в некоторых случаях, вам нужно сделать следующее : echo | whateverCommandsвместо того , чтобы просто whateverCommands(например, я должен был сделать это так: | tail -`echo | whateverCommands`)
Andrew

Ответы:

279

Вы можете использовать evalдля выполнения строки:

eval $illcommando
Арне Бурмейстер
источник
2
Передает ли eval значение, возвращаемое командой ( возвращаемое значение , а не вывод строки)?
Томаш Зато - Восстановить Монику
3
evalэто злая команда во всех языках программирования, поэтому используйте ее с осторожностью.
Кришнадас ПК
1
eval "$illcommando", с кавычками , чтобы ваша команда не искалечилась до ее запуска. Попробуйте evalиспользовать значение illcommando='printf "%s\n" " * "'с и без кавычек, чтобы увидеть разницу.
Чарльз Даффи
@ TomášZato-ReinstateMonica Да, он пересылает возвращаемое значение команды. Однако он НЕ устанавливает "${PIPESTATUS[@]}"переменную в bash должным образом. Тем set -o pipefailне менее, правильно вызывает evalвозврат кода завершения сбоя, если команда содержит команду с ошибкой, переданную успешной команде.
Кэмерон Хадсон
Я пытался сделать что-то вроде grep -E '$filter' unfiltered.txt > filtered.txt, я понятия не имел, почему это работает в командной строке и почему с вычисленными значениями это не работает в скрипте bash. Ваш ответ сохранил мой сценарий. Я добавлю сюда также несколько хороших задокументированных примеров, которые я использовал, чтобы лучше понять, как работает eval. linuxhint.com/bash_eval_command
student0495
28

Я обычно помещаю команды в круглые скобки $(commandStr), если это не помогает, я нахожу режим отладки bash отличным, запустите скрипт какbash -x script

Ола
источник
4
Я не уверен, что относится к commandStr, но по крайней мере это не сработало для меня. Лучше использовать полные рабочие примеры.
Робин Маноли,
@RobinManoli Улучшена ясность для тебя.
Андрей
18
your_command_string="..."
output=$(eval "$your_command_string")
echo "$output"
Такман
источник
10

не помещайте свои команды в переменные, просто запустите

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
источник
1
сделал именно это. но там, где у меня были переменные, которые должны идти как один аргумент, я сделал "${arg}". пример: server :: team_l_start = "$ {teamAComm}"
Жоао Портела
1

./me бросает Raise_dead ()

Я искал что-то вроде этого, но мне также нужно было повторно использовать одну и ту же строку минус два параметра, поэтому я получил что-то вроде:

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

Это то, что я использую для мониторинга создания стека тепла в openstack. В этом случае я ожидаю два условия: действие CREATE и состояние COMPLETE в стеке с именем Somestack.

Чтобы получить эти переменные, я могу сделать что-то вроде:

ACTION=$(my_exe action Somestack)
STATUS=$(my_exe status Somestack)
if [[ "$ACTION" == "CREATE" ]] && [[ "$STATUS" == "COMPLETE" ]]
...
cmyster
источник
0

Вот мой скрипт сборки 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

Одинокие ")" отчасти уродливы. Но я понятия не имею, как исправить этот эстетический аспект.

JMI MADISON
источник
0

Чтобы увидеть все команды, которые выполняются сценарием, добавьте -xфлаг в свою строку шабанга и выполните команду в обычном режиме:

#! /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куда-нибудь.

Игаль
источник