ruby bash rake

ruby - Ejecute los comandos bash desde un Rakefile



(4)

Esta pregunta ya tiene una respuesta aquí:

Me gustaría ejecutar una serie de comandos bash desde un Rakefile . Mi shell activo es bash y rake a rake desde bash .

He incluido en mi Rakefile lo siguiente

task :hello do %{echo "World!"} end

pero al ejecutar rake hello no hay salida?

¿Cómo ejecuto los comandos bash desde un Rakefile?

NOTA : Esto no es un duplicado ya que específicamente pregunta cómo ejecutar comandos bash desde un Rakefile .


Creo que la manera en que Rake quiere que esto suceda es con: http://rubydoc.info/gems/rake/FileUtils#sh-instance_method Ejemplo:

task :test do sh "ls" end

La función de rastreo integrada sh se ocupa del valor de retorno del comando (la tarea falla si el comando tiene un valor de retorno distinto de 0) y además también emite los comandos de salida.


Dado que el consenso parece preferir el método #sh de rake, pero OP solicita explícitamente bash, esta respuesta puede ser útil.

Esto es relevante ya que Rake#sh usa la llamada al Kernel#system para ejecutar comandos de shell. Ruby codifica a ese /bin/sh , ignorando el shell configurado por el usuario o $SHELL en el entorno.

Aquí hay una solución alternativa que invoca bash desde /bin/sh , lo que le permite seguir utilizando el método 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 es prestado de los rieles:

https://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/string/strip.rb

Probablemente puedas obtenerlo requiriendo active_support, o tal vez esté autocargado cuando estés en un proyecto de rieles, pero yo estaba usando este fuera de rieles y tuve que definirlo yo mismo.

Hay dos heredocs, uno externo con los marcadores EOS y uno interno con los marcadores BASH .

La forma en que esto funciona es alimentando el inside heredoc entre los marcadores de BASH para el stdin de bash. Tenga en cuenta que se está ejecutando dentro del contexto de /bin/sh , por lo que es un posix heredoc no uno de ruby. Normalmente eso requiere que el marcador final esté en la columna 1, que no es el caso aquí debido a la sangría.

Sin embargo, como está envuelto dentro de un strip_heredoc heredoc, el método strip_heredoc aplicado allí lo deinyecta, colocando la totalidad del lado izquierdo del heredoc interno en la columna 1 antes de que /bin/sh vea.

/bin/sh también normalmente expandiría variables dentro del heredoc, lo que podría interferir con el script. Las comillas simples alrededor del marcador de inicio, ''BASH'', le indican a /bin/sh no expanda nada dentro del heredoc antes de pasarlo a bash.

Sin embargo, /bin/sh todavía aplica escapes a la cadena antes de pasarlo a bash. Eso significa que los escapes de barra invertida tienen que duplicarse para pasar de /bin/sh a bash, es decir, / vuelve // .

Las opciones de bash -xeuo pipefail son opcionales.

Los argumentos -euo pipefail indican a bash que se ejecute en modo estricto, lo que detiene la ejecución ante cualquier falla o referencia a una variable indefinida, incluso un comando en una interconexión. Esto devolverá un error al rake, lo que detendrá la tarea de rake. Usualmente esto es lo que quieres. Los argumentos se pueden descartar si quieres un comportamiento bash normal.

La opción -x para bash y {verbose: false} para #sh funcionan en concierto para que rake solo imprima los comandos bash que se ejecutan realmente. Esto es útil si su script bash no está destinado a ejecutarse en su totalidad, por ejemplo, si tiene una prueba que le permite salir graciosamente al principio del script.

Tenga cuidado de no establecer un código de salida que no sea 0 si no desea que la tarea de rake falle. Por lo general, eso significa que no quieres usar ningún || exit || exit construcciones sin establecer el código de salida explícitamente, es decir || exit 0 || exit 0

Si te encuentras con alguna rareza de bash en el camino, apaga el -o pipefail . He visto un poco de bugginess relacionado específicamente cuando se conecta a grep .


Hay varias formas de ejecutar comandos de shell en ruby. Una simple (y probablemente la más común) es usar backticks:

task :hello do `echo "World!"` end

Los Backticks tienen un efecto agradable donde la salida estándar del comando de shell se convierte en el valor de retorno. Entonces, por ejemplo, puedes obtener la salida de ls haciendo esto

shell_dir_listing = `ls`

Pero hay muchas otras formas de llamar comandos de shell y todos tienen ventajas / inconvenientes y funcionan de manera diferente. Este artículo explica las opciones en detalle, pero aquí hay unas posibilidades de resumen rápido:


%{echo "World!"} define una Cadena. Supongo que querías %x{echo "World!"} .

%x{echo "World!"} ejecuta el comando y devuelve la salida (stdout). No verás el resultado. Pero puedes hacer:

puts %x{echo "World!"}

Hay más formas de llamar a un comando del sistema:

  • Backticks: `
  • system( cmd )
  • popen
  • Open3#popen3