Jalankan string sebagai perintah dalam skrip Bash

152

Saya memiliki skrip Bash yang membangun string untuk dijalankan sebagai perintah

Naskah:

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

yang tampaknya tidak memasok argumen dengan benar ke $serverbin.

Output skrip:

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'

jika saya hanya menempelkan perintah /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'(dalam output setelah "runnning:") berfungsi dengan baik.

João Portela
sumber
Perhatikan bahwa dalam beberapa kasus, Anda perlu melakukan: echo | whateverCommandsbukan hanya whateverCommands(misalnya, saya harus melakukannya seperti ini: | tail -`echo | whateverCommands`)
Andrew

Jawaban:

279

Anda dapat menggunakan evaluntuk mengeksekusi string:

eval $illcommando
Arne Burmeister
sumber
2
Apakah eval meneruskan nilai pengembalian perintah ( nilai balik , bukan keluaran string)?
Tomáš Zato - Reinstate Monica
3
evaladalah perintah jahat dalam semua bahasa pemrograman jadi gunakan dengan hati-hati.
Krishnadas PC
1
eval "$illcommando", dengan tanda kutip , agar perintah Anda tidak hancur sebelum dijalankan. Coba evaldengan nilai illcommando='printf "%s\n" " * "'dengan dan tanpa tanda kutip untuk melihat perbedaannya.
Charles Duffy
@ TomášZato-ReinstateMonica Ya, itu meneruskan nilai kembali dari perintah. Namun, itu TIDAK mengatur "${PIPESTATUS[@]}"variabel dalam bash dengan benar. Namun, set -o pipefailapakah benar menyebabkan evaluntuk mengembalikan kode keluar gagal jika perintah berisi perintah gagal disalurkan ke perintah yang berhasil.
Cameron Hudson
Saya mencoba melakukan sesuatu seperti grep -E '$filter' unfiltered.txt > filtered.txt, saya tidak tahu mengapa itu bekerja pada baris perintah dan mengapa dengan nilai yang dihitung tidak bekerja dalam bash script. Jawaban Anda menyelamatkan skrip saya. Saya akan menambahkan di sini juga beberapa contoh terdokumentasi yang bagus yang saya gunakan untuk lebih memahami bagaimana eval bekerja. linuxhint.com/bash_eval_command
student0495
28

Saya biasanya menempatkan perintah dalam tanda kurung $(commandStr), jika itu tidak membantu saya menemukan mode debug bash hebat, jalankan script sebagaibash -x script

Ola
sumber
4
Saya tidak yakin apa yang dimaksud commandStr, tetapi setidaknya ini tidak berhasil untuk saya. Lebih baik jika Anda menggunakan contoh kerja penuh.
Robin Manoli
@RobinManoli Meningkatkan kejelasan untuk Anda.
Andrew
18
your_command_string="..."
output=$(eval "$your_command_string")
echo "$output"
Takman
sumber
10

jangan menaruh perintah Anda dalam variabel, jalankan saja

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
sumber
1
melakukan hal itu. tetapi di mana saya memiliki variabel yang harus pergi seperti argumen tunggal yang saya lakukan "${arg}". contoh: server :: team_l_start = "$ {teamAComm}"
João Portela
1

./me cast cast rais_dead ()

Saya mencari sesuatu seperti ini, tetapi saya juga perlu menggunakan kembali string yang sama minus dua parameter jadi saya akhirnya menemukan sesuatu seperti:

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

Ini adalah sesuatu yang saya gunakan untuk memantau pembuatan heat stack openstack. Dalam hal ini saya mengharapkan dua kondisi, tindakan 'BUAT' dan status 'SELESAI' di tumpukan bernama "Somestack"

Untuk mendapatkan variabel-variabel itu saya bisa melakukan sesuatu seperti:

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

Inilah skrip gradle build saya yang mengeksekusi string yang disimpan di 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

Satu-satunya ")" agak jelek. Tapi saya tidak tahu bagaimana cara memperbaiki aspek astetik itu.

JMI MADISON
sumber
0

Untuk melihat semua perintah yang dijalankan oleh skrip, tambahkan -xbendera ke baris shabang Anda, dan jalankan perintah secara normal:

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

Kemudian jika Anda terkadang ingin mengabaikan hasil debug, arahkan ke stderrsuatu tempat.

Yigal
sumber