J'écris sur un énorme script de fabrique de scripts générant beaucoup de scripts de maintenance pour mes serveurs.
Jusqu'à présent, j'écris quelques lignes qui doivent être écrites sur une seule 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) du 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 de code en ligne que je produis avec heredocs car je les trouve bien meilleurs à é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
Ainsi, 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 pour un hérédoc de se comporter comme echo -ne
sans le symbole de fin de ligne?
sudo
d'un script, vous le faites mal: exécutez le script entier en tant que root à la place!sudo -u USERNAME
sur ce lieu, voir Comment puis-je exécuter une commande « sudo » dans un script? .sudo
sans nom d'utilisateur demande le mot de passe, sauf si vous l'avez tapé, il y a un délai. C'est encore pire si vous n'exécutez pas le script dans un terminal, vous ne pouvez même pas voir la requête de mot de passe et cela ne fonctionnera tout simplement pas. L'sudo -u
approche n'a aucun de ces problèmes.Réponses:
Non, heredoc se termine toujours par une nouvelle ligne. Mais vous pouvez toujours supprimer la dernière nouvelle ligne, par exemple avec Perl:
-p
lit l'entrée ligne par ligne, exécute le code spécifié dans-e
et imprime la ligne (éventuellement modifiée)la source
La réponse courte est que heredoc et herestrings sont juste construits de cette façon, donc non - ici-doc et herestring ajouteront toujours une nouvelle ligne de fin et il n'y a pas d'option ou de méthode native pour la désactiver (peut-être y aura-t-il dans les futures versions bash?).
Cependant, une façon de l'aborder via des méthodes bash uniquement serait de lire ce que heredoc donne via la
while IFS= read -r
méthode standard , mais d'ajouter un délai et d'imprimer la dernière ligne viaprintf
sans la nouvelle ligne de fin. Voici ce que l'on pourrait faire avec bash uniquement:Ce que vous voyez ici est la boucle while habituelle avec
IFS= read -r line
approche, mais 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 commençons l'impression uniquement lorsque nous avons lu la deuxième ligne). De cette façon, nous pouvons capturer la dernière ligne, et lorsque la prochaine itérationread
retourne le statut de sortie 1, c'est lorsque nous imprimons la dernière ligne sans nouvelle ligne viaprintf
. Verbose? Oui. Mais ça marche:Remarquez que le
$
caractère d'invite est poussé vers l'avant, car il n'y a pas de nouvelle ligne. En prime, cette solution est portable et ish Posix, il devrait donc travaillerksh
etdash
aussi bien.la source
Je vous recommande d'essayer une approche différente. Plutôt que de reconstituer votre script généré à partir de plusieurs déclarations d'écho et heredocs. Je vous suggère d'essayer d'utiliser un seul hérédoc.
Vous pouvez utiliser l'expansion variable et la substitution de commandes dans un hérédoc. Comme dans cet exemple:
Je trouve que cela conduit souvent à des résultats finaux beaucoup plus lisibles que la production de la pièce par pièce.
Il semble également 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 qui fonctionne autour de scripts mal formatés, et même dans ce cas, cela pourrait finir par être interprété par un shell différent de celui que vous vouliez.la source
#!
mais mon bloc de code n'est qu'un extrait d'un script de 2000 lignes;) Je ne vois pas en ce moment comment votre suggestion résout mon problème en générant une ligne de code dans une boucle while ...$( ...command...)
intérieur d'un hérédoc, pour insérer la sortie de ces commandes en ligne à ce point dans l'hérédoc; (3) Bash a des variables de tableau, que vous pouvez développer en ligne, et utilisez des substitutions pour ajouter des choses au début / à la fin si nécessaire. Ensemble, cela rend la suggestion de kasperd beaucoup plus puissante (et votre script potentiellement beaucoup plus lisible).Les Heredocs se terminent toujours par une nouvelle ligne, mais vous pouvez simplement supprimer cela. Le moyen le plus simple que je connaisse est avec le
head
programme:la source
-c
prend aussi des valeurs négatives! Comme ça encore plus que lapearl
solutionVous pouvez supprimer les sauts de ligne comme vous le souhaitez, la tuyauterie
tr
serait probablement la plus simple. Bien sûr, cela supprimerait toutes les nouvelles lignes.Mais, l' instruction if que vous créez ne nécessite pas cela, l'expression arithmétique
(( .. ))
devrait fonctionner correctement même si elle contient des retours à la ligne.Donc, vous pourriez faire
produire
Le construire en boucle rend toujours laide, cependant. Le
|| 0
est là bien sûr pour que nous n'ayons pas besoin de cas particulier la première ou la dernière ligne.De plus, vous en avez
| sudo tee ...
dans chaque sortie. Je pense que nous pourrions nous débarrasser de cela en ouvrant une redirection une seule fois (avec substitution de processus), et en l'utilisant pour l'impression ultérieure:Et franchement, je pense toujours que construire des noms de variables à partir de variables dans le script externe (comme ça
\$${name}_E
) est un peu moche, et il devrait probablement être remplacé par un tableau associatif .la source