Je voudrais exécuter un certain nombre de commandes bash
à partir d'un Rakefile
.
J'ai essayé ce qui suit dans mon Rakefile
task :hello do
%{echo "World!"}
end
mais lors de l'exécution de rake hello
il n'y a pas de sortie? Comment exécuter des commandes bash à partir d'un rakefile?
NOTE : Ce n'est pas un doublon car il demande spécifiquement comment exécuter les commandes bash à partir d'un Rakefile .
Je pense que la façon dont Rake veut que cela se produise est avec: http://rubydoc.info/gems/rake/FileUtils#sh-instance_method Exemple:
task :test do
sh "ls"
end
La fonction de râteau intégrée sh prend en charge la valeur de retour de la commande (la tâche échoue si la commande a une valeur de retour autre que 0) et en plus elle génère également la sortie des commandes.
Il existe plusieurs façons d'exécuter des commandes Shell dans Ruby. Un simple (et probablement le plus courant) consiste à utiliser des backticks:
task :hello do
`echo "World!"`
end
Les backticks ont un bel effet où la sortie standard de la commande Shell devient la valeur de retour. Ainsi, par exemple, vous pouvez obtenir la sortie de ls
en faisant
Shell_dir_listing = `ls`
Mais il existe de nombreuses autres façons d'appeler des commandes Shell et elles ont toutes des avantages/inconvénients et fonctionnent différemment. Cet article explique les choix en détail, mais voici un bref résumé des possibilités:
stdout =% x {cmd} - Syntaxe alternative pour les backticks, en coulisses ça fait la même chose
exec (cmd) - Remplacer complètement le processus en cours par un nouveau processus cmd
success = system (cmd) - Exécutez un sous-processus et retournez true/false en cas de succès/échec (basé sur l'état de sortie de cmd)
IO # popen (cmd) {| io |} - Exécutez un sous-processus et connectez stdout et stderr à io
stdin, stdout, stderr = Open3.popen3 (cmd) - Exécutez un sous-processus et connectez-vous à tous les canaux (in, out, err)
Étant donné que le consensus semble préférer le rake #sh
, mais OP demande explicitement bash, cette réponse peut avoir une certaine utilité.
Ceci est pertinent puisque Rake#sh
utilise le Kernel#system
appel pour exécuter les commandes Shell. Ruby hardcodes que pour /bin/sh
, en ignorant le shell configuré par l'utilisateur ou $Shell
dans l'environnement.
Voici une solution de contournement qui appelle bash à partir de /bin/sh
, vous permettant de continuer à utiliser la méthode sh
:
task :hello_world do
sh <<-EOS.strip_heredoc, {verbose: false}
/bin/bash -xeuo pipefail <<'BASH'
echo "Hello, world!"
BASH
EOS
end
class String
def strip_heredoc
gsub(/^#{scan(/^[ \t]*(?=\S)/).min}/, ''.freeze)
end
end
#strip_heredoc
est emprunté à Rails:
https://github.com/Rails/rails/blob/master/activesupport/lib/active_support/core_ext/string/strip.rb
Vous pourriez probablement l'obtenir en exigeant active_support, ou peut-être qu'il est chargé automatiquement lorsque vous êtes dans un projet Rails, mais j'utilisais cela en dehors Rails et ainsi de suite) pour le défendre moi-même.
Il existe deux heredocs, une externe avec les marqueurs EOS
et une interne avec les marqueurs BASH
.
La façon dont cela fonctionne consiste à alimenter l'hérédoc intérieur entre les marqueurs BASH à la stdin de bash. Notez qu'il s'exécute dans le contexte de /bin/sh
, c'est donc un heredoc posix pas un Ruby one. Normalement, cela nécessite que le marqueur de fin soit dans la colonne 1, ce qui n'est pas le cas ici à cause de l'indentation.
Cependant, comme il est enveloppé dans un Ruby heredoc, le strip_heredoc
la méthode qui y est appliquée la désindente, en plaçant l'intégralité du côté gauche de l'hérédoc intérieur dans la colonne 1 avant /bin/sh
le voyant.
/bin/sh
étendrait normalement les variables dans l'hérédoc, ce qui pourrait interférer avec le script. Les guillemets simples autour du marqueur de début, 'BASH', indiquent /bin/sh
pour ne rien développer à l'intérieur de l'hérédoc avant qu'il ne soit passé à bash.
Toutefois /bin/sh
applique toujours des échappements à la chaîne avant de la passer à bash. Cela signifie que les échappements antislash doivent être doublés pour passer par /bin/sh
à bash, c'est-à-dire \
devient \\
.
Les options bash -xeuo pipefail
sont facultatifs.
Le -euo pipefail
les arguments indiquent à bash de s'exécuter en mode strict, ce qui arrête l'exécution en cas d'échec ou de référence à une variable non définie, même une commande dans un pipeline. Cela renverra une erreur au râteau, ce qui arrêtera la tâche de râteau. C'est généralement ce que vous voulez. Les arguments peuvent être supprimés si vous souhaitez un comportement bash normal.
Le -x
option pour bash et {verbose: false}
argument à #sh
fonctionne de concert afin que rake affiche uniquement les commandes bash qui sont réellement exécutées. Ceci est utile si votre script bash n'est pas destiné à s'exécuter dans son intégralité, par exemple s'il a un test qui lui permet de se terminer correctement au début du script.
Veillez à ne pas définir un code de sortie autre que 0 si vous ne souhaitez pas que la tâche de râteau échoue. Cela signifie généralement que vous ne voulez pas utiliser de || exit
construit sans définir explicitement le code de sortie, c'est-à-dire || exit 0
.
Si vous rencontrez des bizarreries bash en cours de route, désactivez le -o pipefail
. J'ai vu un peu de bug lié à cela spécifiquement lors du pipelining vers grep
.
%{echo "World!"}
Définit une chaîne. Je suppose que vous vouliez %x{echo "World!"}
.
%x{echo "World!"}
Exécute la commande et renvoie la sortie (stdout). Vous ne verrez pas le résultat. Mais vous pouvez faire:
puts %x{echo "World!"}
Il existe plusieurs façons d'appeler une commande système:
system( cmd )
popen
Open3#popen3
Il y a deux façons:
sh " expr "
ou
%x( expr )
Gardez à l'esprit que (expr) peut être {expr}, | expr | ou `expr '
La différence est que sh "expr" est une méthode Ruby pour exécuter quelque chose, et% x (expr) est la méthode intégrée Ruby. Le résultat et l'action sont différentes. Voici un exemple
task :default do
value = sh "echo hello"
puts value
value = %x(echo world)
puts value
end
obtenir:
hello # from sh "echo hello"
true # from puts value
world # from puts value
Vous pouvez voir que %x( expr )
ne fera que l'expr Shell, mais la sortie standard ne s'affichera pas à l'écran. Donc, vous feriez mieux d'utiliser%x( expr )
lorsque vous avez besoin du résultat de la commande.
Mais si vous voulez juste faire une commande Shell, je vous recommande d'utiliser sh "expr"
. Parce que sh "irb"
Vous fera entrer dans le shell irb, tandis que %x(irb)
sera mort.