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

У меня есть скрипт 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:»), она будет работать нормально.


person João Portela    schedule 01.03.2010    source источник
comment
Потому что mywiki.wooledge.org/BashFAQ/050   -  person tripleee    schedule 17.07.2016
comment
Обратите внимание, что в некоторых случаях вам нужно сделать: echo | whateverCommands вместо просто whateverCommands (например, мне пришлось сделать это так: | tail -`echo | whateverCommands`)   -  person Andrew    schedule 14.09.2017


Ответы (8)


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

eval $illcommando
person Arne Burmeister    schedule 01.03.2010
comment
Передает ли eval возвращаемое значение команды (возвращаемое значение, а не строковый вывод)? - person Tomáš Zato - Reinstate Monica; 21.04.2015
comment
eval — вредная команда во всех языках программирования, поэтому используйте ее с осторожностью. - person Krishnadas PC; 17.07.2018
comment
eval "$illcommando", с кавычками, чтобы ваша команда не была искажена до ее выполнения. Попробуйте evaling со значением illcommando='printf "%s\n" " * "' с кавычками и без них, чтобы увидеть разницу. - person Charles Duffy; 27.07.2019
comment
@TomášZato-ReinstateMonica Да, он пересылает возвращаемое значение команды. Однако он НЕ устанавливает переменную "${PIPESTATUS[@]}" в bash должным образом. Тем не менее, set -o pipefail правильно заставляет eval возвращать код выхода с ошибкой, если команда содержит ошибочную команду, переданную в успешную команду. - person Cameron Hudson; 14.03.2020
comment
Я пытался сделать что-то вроде grep -E '$filter' unfiltered.txt > filtered.txt, я понятия не имел, почему это работает в командной строке и почему с вычисляемыми значениями это не работает в сценарии bash. Ваш ответ спас мой сценарий. Я также добавлю сюда несколько хороших задокументированных примеров, которые я использовал, чтобы лучше понять, как работает eval. linuxhint.com/bash_eval_command - person student0495; 06.04.2020

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

person Ola    schedule 01.03.2010
comment
Я не уверен, на что ссылается commandStr, но, по крайней мере, у меня это не сработало. Лучше, если вы будете использовать полные рабочие примеры. - person Robin Manoli; 28.11.2013
comment
@RobinManoli Улучшила ясность для тебя. - person Andrew; 14.09.2017

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

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'
person ghostdog74    schedule 01.03.2010
comment
сделал именно это. но там, где у меня были переменные, которые должны идти как один аргумент, я сделал "${arg}". пример: server::team_l_start = ${teamAComm} - person João Portela; 01.03.2010
comment
Для многих задач отладки рекомендуется иметь команду в виде строки. Спасает меня от многих головных болей. - person Zane; 04.07.2021

./me использует метод raise_dead()

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

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

Это то, что я использую для мониторинга создания теплового стека openstack. В этом случае я ожидаю два условия: действие «СОЗДАТЬ» и статус «ЗАВЕРШЕНО» в стеке с именем «Somestack».

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

ACTION=$(my_exe action Somestack)
STATUS=$(my_exe status Somestack)
if [[ "$ACTION" == "CREATE" ]] && [[ "$STATUS" == "COMPLETE" ]]
...
person cmyster    schedule 17.07.2016

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

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

person twitchdotcom slash KANJICODER    schedule 23.05.2019

Чтобы увидеть все команды, которые выполняются сценарием, добавьте флаг -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 куда-нибудь.

person Yigal    schedule 15.07.2020

Для меня 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

person Mayur Gite    schedule 25.08.2020

person    schedule
comment
Выглядит интересно, но мне не подходит. $your_command_string не выполняется. В чем проблема? - person kklepper; 10.05.2021
comment
Решение @cmyster сработало. - person kklepper; 10.05.2021
comment
Работал на меня. Не знаю, куда поставить, но обратите внимание, что вы не ставите пробел перед = как your_command_string ="..." - person Cadoiz; 15.06.2021