Estoy escribiendo en un gran script de fábrica de scripts que genera muchos scripts de mantenimiento para mis servidores.
Hasta ahora escribo algunas líneas que deben escribirse en una línea con, echo -ne
por ejemplo,
echo -n "if (( " | sudo tee -a /usr/local/bin/upgradeAllServers &> /dev/null
# Generate exitCode check for each Server
IFS=" "
COUNT=0
while read -r name ipAddr
do
if(($COUNT != 0))
then
echo -n " || " | sudo tee -a /usr/local/bin/upgradeAllServers &> /dev/null
fi
echo -n "(\$"$name"_E != 0 && \$"$name"_E != 1)" | sudo tee -a /usr/local/bin/upgradeAllServers &> /dev/null
COUNT=$((COUNT+1))
JOBSDONE=$((JOBSDONE+1))
updateProgress $JOBCOUNT $JOBSDONE
done <<< "$(sudo cat /root/.virtualMachines)"
echo " ))" | sudo tee -a /usr/local/bin/upgradeAllServers &> /dev/null
esto me genera un código (si hay, por ejemplo, 2 servidores en mi archivo de configuración) como
if (( ($server1_E != 0 && $server1_E != 1) || ($server2_E != 0 && $server2_E != 1) ))
Todos los demás bloques de código que no necesitan esta escritura en línea del código que produzco con heredocs ya que los encuentro mucho mejores para escribir y mantener. Por ejemplo, después del código superior tengo el resto generado como
cat << EOF | sudo tee -a /usr/local/bin/upgradeAllServers &> /dev/null
then
# Print out ExitCode legend
echo " ExitCode 42 - upgrade failed"
echo " ExitCode 43 - Upgrade failed"
echo " ExitCode 44 - Dist-Upgrade failed"
echo " ExitCode 45 - Autoremove failed"
echo ""
echo ""
fi
EOF
Entonces el bloque de código final se ve así
if (( ($server1_E != 0 && $server1_E != 1) || ($server2_E != 0 && $server2_E != 1) ))
then
# Print out ExitCode legend
echo " ExitCode 42 - upgrade failed"
echo " ExitCode 43 - Upgrade failed"
echo " ExitCode 44 - Dist-Upgrade failed"
echo " ExitCode 45 - Autoremove failed"
echo ""
echo ""
fi
Mi pregunta
¿Hay alguna manera de que un heredoc se comporte de manera similar echo -ne
sin el símbolo de fin de línea?
sudo
un script, lo está haciendo mal: en su lugar, ejecute todo el script como root.sudo -u USERNAME
de eso en su lugar, ver ¿Cómo ejecuto un comando 'sudo' dentro de un script? .sudo
sin nombre de usuario solicita la contraseña, a menos que la haya ingresado, hay un retraso. Es aún peor si no ejecuta el script en una terminal, entonces ni siquiera puede ver la consulta de contraseña y simplemente no funcionará. Elsudo -u
enfoque no tiene ninguno de estos problemas.Respuestas:
No, heredoc siempre termina en una nueva línea. Pero aún puede eliminar la última línea nueva, por ejemplo con Perl:
-p
lee la entrada línea por línea, ejecuta el código especificado-e
e imprime la línea (posiblemente modificada)fuente
La respuesta corta es que heredoc y herestrings se construyen de esa manera, por lo que no, here-doc y herestring agregarán siempre una nueva línea final y no hay una opción o una forma nativa para deshabilitarla (¿tal vez habrá versiones futuras de bash?).
Sin embargo, una forma de abordarlo a través de solo bash sería leer lo que heredoc brinda a través del
while IFS= read -r
método estándar , pero agregar un retraso e imprimir la última líneaprintf
sin la nueva línea final. Esto es lo que se podría hacer con bash-only:Lo que ve aquí es el ciclo while habitual con
IFS= read -r line
enfoque, sin embargo, cada línea se almacena en una variable y, por lo tanto, se retrasa (por lo que omitimos la impresión de la primera línea, la almacenamos y comenzamos a imprimir solo cuando hemos leído la segunda línea). De esa forma podemos capturar la última línea, y cuando en la próxima iteraciónread
regrese el estado de salida 1, es cuando imprimimos la última línea sin nueva línea víaprintf
. Detallado? si. Pero funciona:Observe que el
$
carácter de solicitud se empuja hacia adelante, ya que no hay nueva línea. Como beneficio adicional, esta solución es portátil y POSIX-ish, por lo que debería funcionar enksh
ydash
también.fuente
Te recomiendo que pruebes un enfoque diferente. En lugar de juntar su script generado a partir de múltiples declaraciones de eco y heredocs. Le sugiero que intente usar un solo heredoc.
Puede usar la expansión variable y la sustitución de comandos dentro de un heredoc. Como en este ejemplo:
Creo que esto a menudo conduce a resultados finales mucho más legibles que producir el resultado pieza por pieza.
También parece que has estado olvidando la
#!
línea al comienzo de tus scripts. La#!
línea es obligatoria en cualquier script con formato correcto. Intentar ejecutar un script sin la#!
línea solo funcionará si lo llama desde un shell que funciona con scripts mal formateados, e incluso en ese caso podría terminar siendo interpretado por un shell diferente de lo que pretendía.fuente
#!
he olvidado el pero mi bloque de código es solo un fragmento de un script de 2000 líneas;) No veo en este momento cómo su sugerencia resuelve mi problema generando una línea de código en un bucle while ...$( ...command...)
dentro de un heredoc para insertar la salida de esos comandos en línea en ese punto del heredoc; (3) Bash tiene variables de matriz, que puede expandir en línea, y usar sustituciones para agregar elementos al inicio / final si es necesario. Juntos, esto hace que la sugerencia de kasperd sea mucho más poderosa (y su script potencialmente mucho más legible).Los heredocs siempre terminan en una nueva línea de caracteres, pero simplemente puede eliminar eso. La forma más fácil que conozco es con el
head
programa:fuente
-c
también toma valores negativos! Como eso, incluso más que lapearl
soluciónPuede eliminar las nuevas líneas de la forma que desee, la canalización
tr
probablemente sería la más simple. Esto eliminaría todas las nuevas líneas, por supuesto.Pero, la declaración if que está creando no requiere eso, la expresión aritmética
(( .. ))
debería funcionar bien incluso si contiene nuevas líneas.Entonces, podrías hacer
productor
Sin embargo, construirlo en un bucle todavía es feo. El
|| 0
está ahí, por supuesto, para que no necesitemos un caso especial en la primera o la última línea.Además, tienes eso
| sudo tee ...
en cada salida. Creo que podríamos deshacernos de eso abriendo una redirección solo una vez (con sustitución de proceso) y usándola para la impresión posterior:Y, francamente, sigo pensando que construir nombres de variables a partir de variables en el script externo (como ese
\$${name}_E
) es un poco feo, y probablemente debería reemplazarse con una matriz asociativa .fuente