Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

325
Views
¿Cómo ejecutar un script de shell en Crystal mientras captura la salida?

Quiero ejecutar un script de shell mientras manejo la salida stdout y stderr. Actualmente ejecuto comandos usando Process.run , con shell=false y tres conductos para stdin, stdout y stderr. Engendro fibras para leer desde stdout y stderr y registro (o proceso) la salida. Esto funciona bastante bien para comandos individuales, pero falla horriblemente para scripts.

Simplemente podría configurar shell=true al llamar a Process.run , pero mirando la fuente de Crystal parece que simplemente antepone "sh" a la línea de comandos. Intenté anteponer "bash" y no ayudó.

Cosas como la redirección ( >file ) y tuberías (por ejemplo, curl something | bash ) no parecen funcionar con Process.run

Por ejemplo, para descargar un script de shell y ejecutarlo, probé:

cmd = %{bash -c "curl http://dist.crystal-lang.org/apt/setup.sh " | intento}

Proceso.ejecutar(cmd, ...)

El bash inicial se agregó con la esperanza de que habilitara al operador de tuberías. No parece ayudar. También intenté ejecutar cada comando por separado:

script.split("\n").reject(/^#/, "").each { Process.run(...) }

Pero, por supuesto, eso todavía falla cuando un comando usa redirección o canalizaciones. Por ejemplo, el comando echo "deb http://dist.crystal-lang.org/apt crystal main" >/etc/apt/sources.list.d/crystal.list simplemente genera:

"deb http://dist.crystal-lang.org/apt crystal main" >/etc/apt/sources.list.d/crystal.list`

Podría funcionar si usara el método de ejecución `` backticks en su lugar; pero entonces no podría capturar la salida en tiempo real.

over 4 years ago · Santiago Trujillo
3 answers
Answer question

0

El problema es un problema de UNIX. El proceso principal debe poder acceder a STDOUT del proceso secundario. Usando una tubería, debe iniciar un proceso de shell que ejecutará todo el comando, incluido el | bash y no solo curl $URL . En Cristal esto es:

 command = "curl http://dist.crystal-lang.org/apt/setup.sh | bash" io = MemoryIO.new Process.run(command, shell: true, output: io) output = io.to_s

O si quieres duplicar lo que Crystal hace por ti:

 Process.run("sh", {"-c", command}, output: io)
over 4 years ago · Santiago Trujillo Report

0

Baso mi comprensión en leer el código fuente del archivo run.cr El comportamiento es muy similar al de otros lenguajes en la forma en que maneja los comandos y argumentos.

Sin shell=true , el comportamiento predeterminado de Process.run es usar el comando como ejecutable para ejecutar. Esto significa que la cadena debe ser un nombre de programa, sin ningún argumento, por ejemplo, uname sería un nombre válido ya que hay un programa en mi sistema llamado uname en /usr/bin .

Si alguna vez tuvo el comportamiento de usar con éxito %{bash -c "echo hello world"} con shell=false , entonces algo está mal: el comportamiento predeterminado debería haber sido intentar ejecutar un programa llamado bash -c "echo hello world" , que es poco probable que exista en cualquier sistema.

Una vez que pasa 'shell=true', entonces hace sh -c <command> , lo que permitirá que cadenas como echo hello world como comando funcionen; esto también permitirá que funcionen las redirecciones y las canalizaciones.

El comportamiento shell=true generalmente se puede interpretar como lo siguiente:

 cmd = "sh" args = [] of String args << "-c" << "curl http://dist.crystal-lang.org/apt/setup.sh | bash" Process.run(cmd, args, …)

Tenga en cuenta que estoy usando una matriz de argumentos aquí: sin la matriz de argumentos, no tiene ningún control sobre cómo se pasan los argumentos al shell.

La razón por la que la primera versión, con o sin shell=true no funciona es porque la canalización está fuera de -c , que es el comando que está enviando a bash.

over 4 years ago · Santiago Trujillo Report

0

o si desea llamar a un script de shell y obtener el resultado, acabo de probar con crystal 0.23.1 y ¡funciona!

 def screen output = IO::Memory.new Process.run("bash", args: {"lib/bash_scripts/installation.sh"}, output: output) output.close output.to_s end
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!