Ich möchte eine Reihe von bash
Befehlen von a ausführen Rakefile
.
Ich habe folgendes in meinem versucht Rakefile
task :hello do
%{echo "World!"}
end
aber bei der Ausführung rake hello
gibt es keine Ausgabe? Wie führe ich Bash-Befehle aus einem Rakefile aus?
HINWEIS : Dies ist kein Duplikat, da speziell gefragt wird, wie Bash-Befehle aus einem Rakefile ausgeführt werden sollen .
%{
so%x(
, und das gibt stdout als Zeichenfolge zurück, anstatt es zu drucken.Antworten:
Ich denke, Rake möchte, dass dies geschieht mit: http://rubydoc.info/gems/rake/FileUtils#sh-instance_method Beispiel:
task :test do sh "ls" end
Die eingebaute Rake-Funktion sh kümmert sich um den Rückgabewert des Befehls (die Task schlägt fehl, wenn der Befehl einen anderen Rückgabewert als 0 hat) und gibt zusätzlich die ausgegebenen Befehle aus.
quelle
Es gibt verschiedene Möglichkeiten, Shell-Befehle in Ruby auszuführen. Ein einfaches (und wahrscheinlich das häufigste) ist die Verwendung von Backticks:
task :hello do `echo "World!"` end
Backticks haben einen schönen Effekt, bei dem die Standardausgabe des Shell-Befehls zum Rückgabewert wird. So können Sie beispielsweise die Ausgabe erhalten,
ls
indem Sie dies tunshell_dir_listing = `ls`
Es gibt jedoch viele andere Möglichkeiten, Shell-Befehle aufzurufen, und alle haben Vor- und Nachteile und funktionieren unterschiedlich. In diesem Artikel werden die Auswahlmöglichkeiten ausführlich erläutert. Hier finden Sie eine kurze Zusammenfassung der Möglichkeiten:
stdout =% x {cmd} - Alternative Syntax für Backticks, hinter den Kulissen macht es dasselbe
exec (cmd) - Ersetzen Sie den laufenden Prozess vollständig durch einen neuen cmd-Prozess
success = system (cmd) - Führen Sie einen Unterprozess aus und geben Sie bei Erfolg / Misserfolg true / false zurück (basierend auf dem Status des cmd-Exits).
IO # popen (cmd) {| io | } - Führen Sie einen Unterprozess aus und verbinden Sie stdout und stderr mit io
stdin, stdout, stderr = Open3.popen3 (cmd) - Führen Sie einen Unterprozess aus und stellen Sie eine Verbindung zu allen Pipes her (in, out, err).
quelle
sh "some_task"
den Befehl so drucken lassen, als ob Sie ihn direkt vom Terminal ausgeführt hätten.Angesichts der Tatsache, dass der Konsens die
#sh
Methode von Rake zu bevorzugen scheint , OP jedoch ausdrücklich Bash anfordert, kann diese Antwort von Nutzen sein.Dies ist relevant, da
Rake#sh
derKernel#system
Aufruf zum Ausführen von Shell-Befehlen verwendet wird. Ruby codiert das fest/bin/sh
und ignoriert dabei die konfigurierte Shell des Benutzers oder$SHELL
die Umgebung.Hier ist eine Problemumgehung, mit der bash aufgerufen wird
/bin/sh
, sodass Sie diesh
Methode weiterhin verwenden können :task :hello_world do sh <<-EOS.strip_heredoc, {verbose: false} /bin/bash -xeu <<'BASH' echo "Hello, world!" BASH EOS end class String def strip_heredoc gsub(/^#{scan(/^[ \t]*(?=\S)/).min}/, ''.freeze) end end
#strip_heredoc
wird von Schienen ausgeliehen:https://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/string/strip.rb
Sie könnten es wahrscheinlich erhalten, indem Sie active_support benötigen, oder es wird automatisch geladen, wenn Sie sich in einem Rails-Projekt befinden, aber ich habe diese externen Rails verwendet und musste es daher selbst definieren.
Es gibt zwei Heredocs, einen äußeren mit den Markern
EOS
und einen inneren mit den MarkernBASH
.Die Art und Weise, wie dies funktioniert, besteht darin, den inneren Heredoc zwischen den BASH-Markern dem Bash-Standard zuzuführen. Beachten Sie, dass es im Kontext von ausgeführt wird
/bin/sh
, es ist also ein Posix Heredoc, kein Ruby. Normalerweise muss sich die Endmarkierung in Spalte 1 befinden, was hier aufgrund des Einrückens nicht der Fall ist.Da es jedoch in einen Rubin-Heredoc eingewickelt ist, wird es durch die dort
strip_heredoc
angewandte Methode entfernt und die gesamte linke Seite des inneren Heredocs in Spalte 1 platziert, bevor es/bin/sh
angezeigt wird./bin/sh
würde normalerweise auch Variablen innerhalb des Heredocs erweitern, was das Skript stören könnte. Die einfachen Anführungszeichen um den Startmarker 'BASH' weisen darauf hin, dass/bin/sh
im Heredoc nichts erweitert werden soll, bevor es an bash übergeben wird.Wendet
/bin/sh
jedoch immer noch Escapezeichen auf die Zeichenfolge an, bevor sie an bash übergeben wird. Das bedeutet, dass Backslash-Fluchten verdoppelt werden müssen, um/bin/sh
zu Bash zu gelangen, dh\
zu werden\\
.Die Bash-Optionen
-xeu
sind optional.Die
-eu
Argumente weisen bash an, im strengen Modus ausgeführt zu werden, wodurch die Ausführung bei einem Fehler oder Verweis auf eine undefinierte Variable gestoppt wird. Dies gibt einen Fehler an Rake zurück, wodurch die Rake-Task gestoppt wird. Normalerweise ist dies das, was Sie wollen. Die Argumente können gelöscht werden, wenn Sie ein normales Bash-Verhalten wünschen.Die
-x
Option zum Bash und{verbose: false}
Argumentieren, um gemeinsam zu#sh
arbeiten, sodass Rake nur die Bash-Befehle druckt, die tatsächlich ausgeführt werden. Dies ist nützlich, wenn Ihr Bash-Skript nicht vollständig ausgeführt werden soll, z. B. wenn es einen Test enthält, mit dem es ordnungsgemäß im Skript beendet werden kann.Achten Sie darauf, keinen anderen Exit-Code als 0 festzulegen, wenn die Rake-Task nicht fehlschlagen soll. Normalerweise bedeutet dies, dass Sie keine
|| exit
Konstrukte verwenden möchten, ohne den Exit-Code explizit festzulegen, d|| exit 0
. H.quelle
system(%[xx=$(cat <<EOT\n#{body_text}\nEOT\n); bash <<BASH\n. #{ENV['HOME']}/.bash_profile; echo "$xx" | own_mail -TRm\nBASH\n)]
. Der einfachste Weg wäre jedoch, alles in ein Bash-Skript zu schreiben und es einfach so zu nennensystem("path/my_bash_script.sh")
%{echo "World!"}
definiert einen String. Ich nehme an, du wolltest%x{echo "World!"}
.%x{echo "World!"}
führt den Befehl aus und gibt die Ausgabe zurück (stdout). Sie werden das Ergebnis nicht sehen. Aber Sie können tun:puts %x{echo "World!"}
Es gibt weitere Möglichkeiten, einen Systembefehl aufzurufen:
system( cmd )
popen
Open3#popen3
quelle
%x
und Backticks tatsächlich die äquivalente Ruby-Kernel-Methode aufrufen, sie sind alternative Syntax für dieselbe exakte Methode.system( cmd )
arbeitete für mich. Ich habe versucht, ein PDF-Generator-Skript mit wkhtmltopdf zu schreiben.Es gibt zwei Möglichkeiten:
sh " expr "
oder
%x( expr )
Beachten Sie, dass (Ausdruck) {Ausdruck}, | sein kann Ausdruck | oder `expr`
Der Unterschied ist, dass sh "expr" eine Ruby-Methode ist, um etwas auszuführen, und% x (expr) ist die in Ruby integrierte Methode. Das Ergebnis und die Aktion sind unterschiedlich. Hier ist ein Beispiel
task :default do value = sh "echo hello" puts value value = %x(echo world) puts value end
erhalten:
hello # from sh "echo hello" true # from puts value world # from puts value
Sie können sehen, dass
%x( expr )
nur der Shell-Ausdruck ausgeführt wird, der Standard jedoch nicht auf dem Bildschirm angezeigt wird. Also, du solltest es besser benutzen%x( expr )
wenn Sie das Befehlsergebnis benötigen.Wenn Sie jedoch nur einen Shell-Befehl ausführen möchten, empfehle ich die Verwendung
sh "expr"
. Dennsh "irb"
du wirst in die Irb-Muschel gehen, während%x(irb)
du tot bist .quelle