Edite el script de shell mientras se está ejecutando

¿Puede editar un script de shell mientras se está ejecutando y hacer que los cambios afecten al script en ejecución?

Tengo curiosidad por el caso específico de un script csh que tengo, ese lote ejecuta un montón de versiones de compilación diferentes y se ejecuta toda la noche. Si se me ocurre algo en mitad de la operación, me gustaría ingresar y agregar comandos adicionales, o comentar los que no se han ejecutado.

Si no es posible, ¿existe algún mecanismo de shell o por lotes que me permita hacer esto?

Por supuesto que lo he probado, pero pasarán horas antes de que vea si funcionó o no, y tengo curiosidad por saber qué está sucediendo o no entre bastidores.

preguntado el 03 de agosto de 10 a las 12:08

He visto dos resultados al editar el archivo de secuencia de comandos para una secuencia de comandos en ejecución: 1) los cambios se ignoran como si hubiera leído todo en la memoria o 2) la secuencia de comandos falla con un error como si hubiera leído parte del comando. No sé si eso depende del tamaño del guión. De cualquier manera, no lo intentaría. -

En resumen: no, a menos que sea autorreferencial / llamada, en cuyo caso el script principal seguirá siendo el anterior. -

Aquí hay dos preguntas importantes. 1) ¿Cómo puedo agregar comandos de manera correcta y segura a un script en ejecución? 2) Cuando modifico un script en ejecución, ¿qué pasará? -

La pregunta es si un shell ejecuta un script leyendo todo el archivo del script y luego ejecutándolo, o leyéndolo parcialmente mientras se ejecuta. No sé cuál es; puede que ni siquiera se especifique. Debe evitar depender de cualquiera de los dos comportamientos. -

11 Respuestas

Los scripts no funcionan de esa manera; la copia en ejecución es independiente del archivo fuente que está editando. La próxima vez que se ejecute el script, se basará en la versión guardada más recientemente del archivo de origen.

Puede ser conveniente dividir este script en varios archivos y ejecutarlos individualmente. Esto reducirá el tiempo de ejecución hasta el fallo. (es decir, divida el lote en una versión de scripts de compilación, ejecutando cada uno individualmente para ver cuál está causando el problema).

Respondido 03 ago 10, 16:08

He observado lo contrario. La ejecución de scripts de bash que se editan puede hacer que el script en ejecución se bloquee porque el archivo parece moverse debajo de la posición del archivo de lectura de script de bash. - tilman vogel

En mi experiencia en múltiples sistemas, la copia en ejecución NO es independiente del archivo de disco, por eso este problema es tan sorprendente e importante en la programación de scripts de shell. - Chris Quenelle

Definitivamente es no independiente del archivo en disco. El shell normalmente lee los scripts en bloques de, por ejemplo, 128 bytes o 4096 bytes o 16384 bytes, y solo lee el siguiente bloque cuando necesita una nueva entrada. (Puede hacer cosas como lsof en un shell ejecutando un script y ver que todavía tiene el archivo abierto). Mirabilios

No. En realidad, si edita un script, el proceso falla. - erik aronesty

No tienes razón. Se almacena en búfer según la implementación y el comando real que se llama en el script, ya sea que stdout se redirija a un archivo, hay muchos factores y su respuesta no es simplemente correcta. - GL2014

It afectar, al menos golpear en mi entorno, pero en forma muy desagradable. Vea estos códigos. Primero a.sh:

#!/bin/sh

echo "First echo"
read y

echo "$y"

echo "That's all."

b.sh:

#!/bin/sh

echo "First echo"
read y

echo "Inserted"

echo "$y"

# echo "That's all."

Do

$ cp a.sh run.sh
$ ./run.sh
$ # open another terminal
$ cp b.sh run.sh  # while 'read' is in effect
$ # Then type "hello."

En mi caso, la salida es siempre:

hola hola Eso es todo. Eso es todo.

(Por supuesto, es mucho mejor automatizarlo, pero el ejemplo anterior es legible).

[editar] Esto es impredecible, por lo tanto peligroso. El la mejor solución es , Como se describe aquí poner todo en una llave, y antes de la llave de cierre, poner "salida". Lea bien la respuesta vinculada para evitar trampas.

[agregado] El comportamiento exacto depende de una nueva línea adicional, y quizás también de su versión Unix, sistema de archivos, etc. Si simplemente desea ver algunas influencias, simplemente agregue "echo foo / bar" a b.sh antes y / o después la línea "leer".

contestado el 04 de mayo de 20 a las 01:05

Mh, no veo el afecto. ¿Me estoy perdiendo de algo? - usuario desconocido

El comportamiento exacto depende de una nueva línea extra, y quizás también en el sabor de Unix, sistema de archivos, etc., aunque no estoy seguro en absoluto. Si simplemente desea ver alguna influencia, simplemente amplíe b.sh agregando 10 líneas de echo foo / bar / baz. La esencia de las respuestas de dave4220 y yo es que el efecto no es fácil de predecir. (Por cierto, el sustantivo "afecto" significa "amor" =) - Teika Kazura

sí, está muy roto. tengo una solución (abajo). lo que es aún más peligroso son las actualizaciones de svn / rsync / git - erik aronesty

Prueba esto ... crea un archivo llamado bash-is-odd.sh:

#!/bin/bash
echo "echo yes i do odd things" >> bash-is-odd.sh

Eso demuestra que bash está, de hecho, interpretando el guión "sobre la marcha". De hecho, editar un script de larga duración tiene resultados impredecibles, inserta caracteres aleatorios, etc. ¿Por qué? Debido a que bash lee desde la última posición del byte, la edición cambia la ubicación del carácter actual que se está leyendo.

Bash es, en una palabra, muy, muy inseguro debido a esta "característica". svn y rsync cuando se usan con scripts bash son particularmente preocupantes, porque por defecto "fusionan" los resultados ... editando en su lugar. rsync tiene un modo que corrige esto. svn y git no.

Presento una solución. Crea un archivo llamado /bin/bashx:

#!/bin/bash
source "$1"

Ahora usa #!/bin/bashx en sus scripts y siempre ejecútelos con bashx en lugar de bash. Esto soluciona el problema; puede rsync sus guiones.

Solución alternativa (en línea) propuesta / probada por @ AF7:

{
   # your script
exit $?
} 

Los tirantes rizados protegen contra ediciones y la salida protege contra anexos. Por supuesto, todos estaríamos mucho mejor si bash viniera con una opción, como -w (archivo completo), o algo que hizo esto.

respondido 18 mar '21, 13:03

Por cierto; aquí hay un plus para contrarrestar el menos y porque me gusta tu respuesta editada. - Andrew barbero

No puedo recomendar esto. En esta solución, los parámetros posicionales se cambian en uno. Recuerde también que no puede asignar un valor a $ 0. Significa que si simplemente cambia "/ bin / bash" a "/ bin / bashx", muchos scripts fallan. - Teika Kazura

Por favor, dígame que esta opción ya se implementó. - AF7

Una solución simple, que me sugirió mi amigo Giulio (créditos donde se deben) es insertar {al principio y} al final del scritp. Bash se ve obligado a leer todo lo que tiene en la memoria. - AF7

@ AF7 mejorando la solución de su amigo: {your_code; } && Salida; evitará que las líneas agregadas al final también se ejecuten. - Korkman

Divida su secuencia de comandos en funciones, y cada vez que se llame a una función, source de un archivo separado. Luego, puede editar los archivos en cualquier momento y su secuencia de comandos en ejecución recogerá los cambios la próxima vez que se obtenga.

foo() {
  source foo.sh
}
foo

Respondido 03 ago 10, 19:08

He estado usando esta técnica de manera efectiva durante un tiempo para actualizar mis scripts de compilación de larga ejecución mientras se ejecutan. Me encantaría aprender una técnica para hacer que el archivo actual se lea hasta el final del archivo, de modo que no tenga que tener dos archivos para implementar cada script de shell. - Chris Quenelle

¡Buena pregunta! Espero que este sencillo script ayude

#!/bin/sh
echo "Waiting..."
echo "echo \"Success! Edits to a .sh while it executes do affect the executing script! I added this line to myself during execution\"  " >> ${0}
sleep 5
echo "When I was run, this was the last line"

En Linux, parece que los cambios realizados en un .sh en ejecución son ejecutados por el script en ejecución, ¡si puede escribir lo suficientemente rápido!

Respondido el 06 de Septiembre de 18 a las 05:09

Una nota al margen interesante: si está ejecutando un script de Python, no cambia. (Esto probablemente sea descaradamente obvio para cualquiera que entienda cómo el shell ejecuta los scripts de Python, pero pensó que podría ser un recordatorio útil para alguien que busque esta funcionalidad).

Yo creé:

#!/usr/bin/env python3
import time
print('Starts')
time.sleep(10)
print('Finishes unchanged')

Luego, en otro shell, mientras está inactivo, edite la última línea. Cuando esto se completa, muestra la línea inalterada, presumiblemente porque está ejecutando un .pyc? Lo mismo sucede en Ubuntu y macOS.

respondido 09 nov., 18:14

No tengo csh instalado, pero

#!/bin/sh
echo Waiting...
sleep 60
echo Change didn't happen

Ejecuta eso, edita rápidamente la última línea para leer

echo Change happened

La salida es

Waiting...
/home/dave/tmp/change.sh: 4: Syntax error: Unterminated quoted string

Hrmph.

Supongo que las ediciones de los scripts de shell no tienen efecto hasta que se vuelven a ejecutar.

Respondido 03 ago 10, 16:08

debe poner la cadena que desea mostrar entre comillas. - user1463308

de hecho, demuestra que su editor no funciona de la manera que piensa. muchos, muchos editores (incluidos vim, emacs) operan en un archivo "tmp" y no en el archivo en vivo. Intente usar "echo 'echo uh oh' >> myshell.sh" en lugar de vi / emacs ... y observe cómo genera el material nuevo. Peor ... ¡svn y rsync también editan de esta manera! - erik aronesty

-1. Ese error no está relacionado con el archivo que se está editando: ¡es porque estás usando un apóstrofo! Eso actúa como una comilla simple, provocando el error. Pon toda esa cadena entre comillas dobles y vuelve a intentarlo. - Pingüino anónimo

El hecho de que se haya producido el error muestra que la edición no tuvo el efecto deseado. - danmcardle

@danmcardle ¿Quién sabe? Tal vez bash vio Change didn'ned. - Kirill Bulyguin

Si todo esto está en un solo script, entonces no, no funcionará. Sin embargo, si lo configura como un script de controlador que llama a subguiones, es posible que pueda cambiar un subguión antes de que se llame, o antes de que se vuelva a llamar si está en bucle, y en ese caso creo que esos cambios se reflejaría en la ejecución.

Respondido 03 ago 10, 17:08

Escucho que no ... pero ¿qué pasa con algunas indirectas?

BatchRunner.sh

Command1.sh
Command2.sh

Comando1.sh

runSomething

Comando2.sh

runSomethingElse

Entonces debería poder editar el contenido de cada archivo de comando antes de que BatchRunner llegue a él, ¿verdad?

O

Una versión más limpia haría que BatchRunner buscara un solo archivo en el que se ejecutaría consecutivamente una línea a la vez. Entonces debería poder editar este segundo archivo mientras el primero se está ejecutando, ¿verdad?

Respondido 03 ago 10, 17:08

Me pregunto si los carga en la memoria para ejecutarlos y un cambio no importa una vez que se inicia el proceso principal ... - eric hodonsky

Utilice Zsh en su lugar para sus scripts.

AFAICT, Zsh no exhibe este comportamiento frustrante.

Respondido 01 Abr '20, 00:04

Esta es la razón # 473 para preferir Zsh a bash. Recientemente he estado trabajando en un antiguo script de bash que tarda 10 m en ejecutarse, ¡y no puedo editarlo mientras espero a que se complete! - Miqueas Elliott

por lo general, es poco común editar su script mientras se está ejecutando. Todo lo que tiene que hacer es poner bajo control sus operaciones. Utilice declaraciones if / else para comprobar las condiciones. Si algo falla, haz esto, de lo contrario haz aquello. Ese es el camino a seguir.

Respondido 03 ago 10, 16:08

En realidad, se trata menos de errores de scripts que de decidir modificar el trabajo por lotes en mitad de la operación. IE se da cuenta de que hay más que quiero compilar, o que no necesito ciertos trabajos que ya están en cola. - acuse de recibo

Si tu estrictamente anexar a los scripts, ¡entonces bash hará lo que esperas! - erik aronesty

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.