Sí, los shells, y bash
en particular, tienen cuidado de leer el archivo de una línea a la vez, por lo que funciona igual que cuando lo usa de forma interactiva.
Notará que cuando el archivo no se puede buscar (como una tubería), bash
incluso lee un byte a la vez para asegurarse de no leer más allá del \n
carácter. Cuando se puede buscar el archivo, se optimiza leyendo bloques completos a la vez, pero se vuelve a buscar después de \n
.
Eso significa que puedes hacer cosas como:
bash << \EOF
read var
var's content
echo "$var"
EOF
O escriba guiones que se actualicen a sí mismos. Lo que no podría hacer si no le brindara esa garantía.
Ahora, es raro que desee hacer cosas así y, como descubrió, esa característica tiende a interferir con más frecuencia de lo que es útil.
Para evitarlo, puede intentar 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
esté en la misma línea que }
; aunque también podría ponerlo dentro de los corchetes justo antes del cierre).
o:
main() {
sleep 20
echo test
}
main "$@"; exit
El shell necesitará leer el script hasta exit
antes de comenzar a hacer algo. Eso asegura que el shell no volverá a leer el script.
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 juego de caracteres que estaba vigente en el momento en que se analizó el comando, que en este caso es antes de queexport
se ejecute el comando.
También tenga en cuenta que si se usa el comando source
aka .
, con algunos shells, tendrá el mismo tipo de problema para los archivos de origen.
Sin bash
embargo, ese no es el caso de cuyo source
comando lee el archivo completamente antes de interpretarlo. Si escribe 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 me basaría en eso, ya que podría imaginar que las versiones futuras de bash
podrían cambiar ese comportamiento que actualmente puede verse como una limitación (bash y AT&T ksh son los únicos shells similares a POSIX que se comportan así hasta donde se sabe) y el already_sourced
truco es un poco frágil, ya que supone que la variable no está en el entorno, sin mencionar que afecta el contenido de la variable BASH_SOURCE)
\n
haría el truco? Tal vez una subshell()
servirá? No tengo mucha experiencia, ¡por favor ayuda!sleep 20 ;\n echo test ;\n sleep 20
y empiezo a editarlo, puede comportarse mal. Por ejemplo, bash podría leer los primeros 10 bytes del script, comprender elsleep
comando y dormir. Después de que se reanude, habrá diferentes contenidos en el archivo a partir de 10 bytes.