Por lo general, si edita un script, todos los usos en ejecución del script son propensos a errores.
Según tengo entendido, bash (¿otros shells también?) Lee el script de forma incremental, por lo que si modificaste el archivo del script externamente, comienza a leer cosas incorrectas. ¿Hay alguna forma de prevenirlo?
Ejemplo:
sleep 20
echo test
Si ejecuta este script, bash leerá la primera línea (digamos 10 bytes) y se irá a dormir. Cuando se reanuda, puede haber diferentes contenidos en el script a partir del décimo byte. Puede que esté en medio de una línea en el nuevo guión. Por lo tanto, el script en ejecución se romperá.
Respuesta aceptada:
Sí, conchas y bash
en particular, tenga cuidado de leer el archivo una línea a la vez, para que funcione igual que cuando lo usa de forma interactiva.
Notarás que cuando el archivo no se puede buscar (como una canalización), bash
incluso lee un byte a la vez para asegurarse de no leer más allá del \n
personaje. Cuando se puede buscar el archivo, se optimiza leyendo bloques completos a la vez, pero vuelve a buscar después del \n
.
Eso significa que puedes hacer cosas como:
bash << \EOF
read var
var's content
echo "$var"
EOF
O escriba scripts que se actualicen solos. Cosa que no podrías hacer si no te diera esa garantía.
Ahora, es raro que desee hacer cosas como esa y, como descubrió, esa característica tiende a ser un estorbo más a menudo de lo que es útil.
Para evitarlo, puede intentar y asegurarse de no modificar el archivo en el lugar (por ejemplo, modificar una copia y mover la copia en su lugar (como sed -i
o perl -pi
y algunos editores lo hacen, por ejemplo)).
O podrías escribir tu guión como:
{
sleep 20
echo test
}; exit
(tenga en cuenta que es importante que exit
estar en la misma línea que }
; aunque también podrías ponerlo dentro de las llaves justo antes del cierre).
o:
main() {
sleep 20
echo test
}
main "[email protected]"; exit
El shell necesitará leer el script hasta que exit
antes de empezar a hacer nada. Eso asegura que el shell no volverá a leer el script.
Sin embargo, eso significa que todo el script se almacenará en la memoria.
Eso también puede afectar el análisis del script.
Por ejemplo, en bash
:
export LC_ALL=fr_FR.UTF-8
echo $'St\ue9phane'
Daría salida a ese U+00E9 codificado en UTF-8. Sin embargo, si lo cambia a:
{
export LC_ALL=fr_FR.UTF-8
echo $'St\ue9phane'
}
El \ue9
se expandirá en el conjunto de caracteres que estaba en vigor en el momento en que se analizó el comando, que en este caso es antes la export
se ejecuta el comando.
También tenga en cuenta que si la source
también conocido como .
se usa el comando, con algunos shells, tendrá el mismo tipo de problema para los archivos fuente.
Ese no es el caso de bash
aunque cuyo source
El comando lee el archivo completamente antes de interpretarlo. Si escribe para bash
específicamente, podría hacer uso de eso agregando al comienzo del script:
if [[ ! $already_sourced ]]; then
already_sourced=1
source "$0"; exit
fi
(Sin embargo, no confiaría en eso, ya que puedes imaginar futuras versiones de bash
podría cambiar ese comportamiento que actualmente se puede ver como una limitación (bash y AT&T ksh son los únicos shells similares a POSIX que se comportan así hasta donde puedo decir) y el already_sourced
el truco es un poco frágil ya que asume que la variable no está en el entorno, sin mencionar que afecta el contenido de la variable BASH_SOURCE)