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 Kernel#system
para ejecutar comandos de shell. Ruby codifica a cero el /bin/sh
, ignorando el shell configurado del usuario o $SHELL
en el entorno.
He aquí una solución que invoca fiesta de /bin/sh
, lo que le permite seguir utilizando el sh
método:
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 tomada de rieles:
https://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/string/strip.rb
Probablemente se podría conseguirlo por requiriendo active_support, o tal vez esté autocargado cuando estás en un proyecto de rieles, pero yo estaba usando esto fuera de rieles y tuve que definirlo yo mismo.
Hay dos heredos, uno externo con los marcadores EOS
y uno interior con los marcadores BASH
.
La forma en que esto funciona es alimentando el interior heredoc entre los marcadores de BASH a la base de datos 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 rubro 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 /bin/sh
al verlo.
/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', indican /bin/sh
que no se debe expandir nada dentro del heredoc antes de pasarlo a bash.
Sin embargo, /bin/sh
sigue aplicando escapes a la cadena antes de pasarla a bash. Eso significa que los escapes de barra invertida deben duplicarse para pasar el /bin/sh
a bash, es decir\
se convierte en \\
.
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 canalizació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}
argumento 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 desea utilizar ninguna construcción || exit
sin establecer explícitamente el código de salida, es decir, || 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 con el pipeline al grep
.
No es '% {', es '% x (', y eso devuelve stdout como una cadena en lugar de imprimirlo. –
No es un duplicado como se indicó anteriormente, ya que específicamente solicita la ejecución en un archivo de rake y no en un programa regular de ruby – Gizmomogwai
¿Cómo es que está marcado como un duplicado cuando pregunta específicamente sobre Rake en lugar de Ruby en general ?! – silverdr