J'écris sur un énorme script de script d'usine qui génère de nombreux scripts de maintenance pour mes serveurs.
Jusqu’à présent, j’écris des lignes qui doivent être écrites sur une ligne avec echo -ne
par exemple.
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
cela me génère (s'il y a par exemple 2 serveurs dans mon fichier de configuration) un code comme
if (( ($server1_E != 0 && $server1_E != 1) || ($server2_E != 0 && $server2_E != 1) ))
Tous les autres blocs de code qui n'ont pas besoin de cette écriture en ligne que je produis avec heredocs puisque je les trouve beaucoup mieux à écrire et à maintenir. Par exemple. après le code supérieur, j'ai le reste généré comme
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
Donc, le bloc de code final ressemble à
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
Ma question
Existe-t-il un moyen d’avoir un comportement heredoc similaire à echo -ne
sans le symbole de fin de ligne?
Non, Heredoc se termine toujours par une nouvelle ligne. Mais vous pouvez toujours supprimer la dernière nouvelle ligne, par exemple avec Perl:
cat << 'EOF' | Perl -pe 'chomp if eof'
First line
Second line
EOF
Existe-t-il un moyen pour un comportement heredoc similaire à echo -ne sans le symbole de fin de ligne?
La réponse courte est que heredoc et herestrings sont juste construits de cette façon, donc non - here-doc et herestring ajouteront toujours une nouvelle ligne de fin et il n'y a pas d'option ou de méthode native pour le désactiver (peut-être qu'il y aura dans les futures versions de bash?).
Cependant, une façon de l'aborder via des méthodes uniquement bash serait de lire ce que heredoc donne via la méthode standard while IFS= read -r
, mais d'ajouter un délai et d'imprimer la dernière ligne via printf
sans le retour à la ligne final. Voici ce que l'on pourrait faire avec bash-only:
#!/usr/bin/env bash
while true
do
IFS= read -r line || { printf "%s" "$delayed";break;}
if [ -n "$delayed" ];
then
printf "%s\n" "$delayed"
fi
delayed=$line
done <<EOF
one
two
EOF
Ce que vous voyez ici est la boucle while habituelle avec l'approche IFS= read -r line
. Cependant, chaque ligne est stockée dans une variable et donc retardée (nous sautons donc l'impression de la première ligne, la stockons et ne commençons à imprimer que lorsque nous avons lu la deuxième ligne). De cette façon, nous pouvons capturer la dernière ligne, et quand à la prochaine itération read
renvoie le statut de sortie 1, nous imprimons la dernière ligne sans nouvelle ligne via printf
name__. Verbose? Oui. Mais ça marche:
$ ./strip_heredoc_newline.sh
one
two$
Notez que le caractère d'invite $
est avancé car il n'y a pas de nouvelle ligne. En prime, cette solution est portable et POSIX-ish, elle devrait donc fonctionner également avec ksh
et dash
name__.
$ dash ./strip_heredoc_newline.sh
one
two$
Je vous recommande d'essayer une approche différente. Plutôt que de reconstituer votre script généré à partir de plusieurs instructions echo et heredocs. Je vous suggère d'essayer d'utiliser un seul heredoc.
Vous pouvez utiliser le développement variable et la substitution de commandes dans un heredoc. Comme dans cet exemple:
#!/bin/bash
cat <<EOF
$USER $(uname)
EOF
Je trouve que cela conduit souvent à des résultats finaux beaucoup plus lisibles que la production pièce par pièce.
En outre, il semble que vous ayez oublié la ligne #!
au début de vos scripts. La ligne #!
est obligatoire dans tous les scripts correctement formatés. Tenter d'exécuter un script sans la ligne #!
ne fonctionnera que si vous l'appelez à partir d'un shell fonctionnant avec des scripts mal formatés. Même dans ce cas, il pourrait être interprété par un shell différent de celui souhaité.
Heredocs se termine toujours par une nouvelle ligne de caractères, mais vous pouvez simplement l'enlever. Le moyen le plus simple que je connaisse est d'utiliser le programme head
:
head -c -1 <<EOF | Sudo tee file > /dev/null
my
heredoc
content
EOF
Vous pouvez supprimer les nouvelles lignes de la manière qui vous convient, la tuyauterie vers tr
serait probablement la plus simple. Cela supprimerait toutes les nouvelles lignes, bien sûr.
$ tr -d '\n' <<EOF
if ((
EOF
Cependant, l'instruction si que vous construisez ne l'exige pas, l'expression arithmétique (( .. ))
devrait fonctionner correctement, même si elle contient des nouvelles lignes.
Alors tu pourrais faire
cat <<EOF
if ((
EOF
for name in x y; do
cat << EOF
( \$${name}_E != 0 && \$${name}_E != 1 ) ||
EOF
done
cat <<EOF
0 )) ; then
echo do something
fi
EOF
produisant
if ((
( $x_E != 0 && $x_E != 1 ) ||
( $y_E != 0 && $y_E != 1 ) ||
0 )) ; then
echo do something
fi
Construire dans une boucle fait toujours moche, cependant. Le || 0
est bien sûr là pour que nous n’ayons pas besoin de cas spécial la première ou la dernière ligne.
En outre, vous avez ce | Sudo tee ...
dans chaque sortie. Je pense que nous pourrions nous en débarrasser en ouvrant une redirection une seule fois (avec substitution de processus) et en l'utilisant pour l'impression ultérieure:
exec 3> >(Sudo tee outputfile &>/dev/null)
echo output to the pipe like this >&3
echo etc. >&3
exec 3>&- # close it in the end
Et franchement, je pense toujours que la construction de noms de variables à partir de variables du script externe (comme celui-ci \$${name}_E
) est un peu moche, et elle devrait probablement être remplacée par un tableau associatif .