Sur une machine Linux, j'ai une série de commandes qui offrent des valeurs numériques de l'état de différents capteurs.
L'appel de ces commandes ressemble à ce qui suit:
$ command1
5647
$ command2
76
$ command3
8754
Ces valeurs changent en temps réel, et chaque fois que je veux vérifier l'état de l'une d'entre elles, je dois relancer la commande ... Cela ne me fait aucun bien car j'ai besoin des deux mains pour manipuler le matériel.
Mon objectif est de créer un simple script Bash qui appelle ces commandes et garde la valeur mise à jour (en temps réel de manière asynchrone ou en actualisant la valeur toutes les x secondes) comme ceci:
$ ./myScript.sh
command1: x
command2: y
command3: z
command4: v
Où x
, y
, z
et v
sont les valeurs changeantes.
Bash permet cela simplement et efficacement? ou devrais-je choisir de le faire dans une autre langue, comme Python?
MISE À JOUR avec plus d'informations:
Mon script actuel est:
#!/bin/bash
echo "Célula calibrada: " $(npe ?AI1)
echo "Anemómetro: " $(npe ?AI2)
echo "Célula temperatura: " $(npe ?AI3)
echo "Célula temperatura: " $(npe ?AI4)
npe
étant un exemple de commande qui renvoie la valeur numérique. J'attends une sortie comme celle-ci:
Cette sortie que j'obtiens avec la commande watch -n x ./myScript.sh
, où x
est la valeur de rafraîchissement des secondes. Si je modifie mon script comme ceci:
#!/bin/bash
while sleep 1; do
clear; # added to keep the information in the same line
echo "Célula calibrada: " $(npe ?AI1);
echo "Anemómetro: " $(npe ?AI2);
echo "Célula temperatura: " $(npe ?AI3);
echo "Célula temperatura: " $(npe ?AI4);
done
J'obtiens ma sortie avec un scintillement ennuyeux:
Il peut être difficile d'implémenter une solution en temps réel dans bash.
Il existe de nombreuses façons d'exécuter un script une fois toutes les X secondes, vous pouvez utiliser watch
. Je suppose que vous avez déjà myScript.sh
disponible. Remplacez X par le nombre de secondes dont vous avez besoin.
watch -n X ./myScript.sh
while sleep X; do ./myScript.sh; done
upd. pour émuler la montre, vous souhaiterez peut-être effacer l'écran entre les itérations. à l'intérieur du script, il ressemblera à ceci:
while sleep X; do
clear;
command1;
command2;
done
ajoutez l'une des options ci-dessus au script lui-même.
Vous pouvez utiliser tput cup 0 0
pour envoyer le curseur en haut à gauche de l'écran. clear
une fois.
#!/bin/bash
clear
while sleep 1; do
tput cup 0 0
printf "%21s %6d \n" \
"Célula calibrada: " $(npe ?AI1) \
"Anemómetro: " $(npe ?AI2) \
"Célula temperatura: " $(npe ?AI3) \
"Célula temperatura: " $(npe ?AI4)
done
Je suppose que le scintillement est dû au fait que vos commandes prennent un moment pour renvoyer leurs valeurs. Voici ma solution de contournement habituelle:
cmds(){
echo "Célula calibrada: " $(npe ?AI1);
echo "Anemómetro: " $(npe ?AI2);
echo "Célula temperatura: " $(npe ?AI3);
echo "Célula temperatura: " $(npe ?AI4);
}
while true; do
out="$(cmds)"
clear
echo "$out"
sleep 1
done
L'idée étant que nous effacions l'écran au dernier moment possible.
Si vous clear
immédiatement après le sleep
, plutôt qu'immédiatement avant, vous pourrez lire le résultat plus facilement:
#!/bin/sh
while sleep 1
do
clear
echo "Célula calibrada: " $(npe ?AI1)
echo "Anemómetro: " $(npe ?AI2)
echo "Célula temperatura: " $(npe ?AI3)
echo "Célula temperatura: " $(npe ?AI4)
done
Cependant, je supprimerais la boucle ici et utiliserais watch
pour exécuter le script à plusieurs reprises. C'est une composition plus flexible d'outils individuels.
Vous pouvez le faire exactement en bash. Si le texte clignote toujours, vous n'avez pas lu complètement les réponses précédentes.
Vous devez clear
l'écran avant vous faites écho aux nouvelles valeurs, pas après.
Vous êtes: afficher une ligne, puis exécuter la commande pour afficher la suivante.
Vous devez: exécuter toutes les commandes (sans toucher l'écran) et enregistrer les résultats dans 4 var, puis effacer et afficher ces 4 résultats à la fois.
Si je modifie votre propre script, essayez:
#!/bin/bash
while sleep 1; do
# facultative?# tput cup 0 0
ccab="$(npe ?AI1)"
cane="$(npe ?AI2)"
ctemp="$(npe ?AI3)"
ctemp2="$(npe ?AI4)"
clear
printf "%21s %6d \n" \
"Célula calibrada: " "$ccab" \
"Anemómetro: " "$cane" \
"Célula temperatura: " "$temp" \
"Célula temperatura: " "$temp2"
done
Ici, la longue exécution des 4 requêtes a lieu sans changer l'affichage, puis l'affichage est rafraîchi très rapidement et affiché tout d'un coup avec les 4 nouvelles valeurs.
vous pouvez mettre toutes vos commandes dans la boucle while avec un certain temps de sommeil. Dans l'exemple ci-dessous, je mets en veille toutes les 2 secondes. La commande date s'exécutera donc toutes les 2 secondes
#!/bin/bash
while (true)
do
echo "Date & Time : $(date)"
sleep 2
done
Cela fait 50 lignes sans scintillement, car il utilise tput pour mettre à jour chaque ligne séparément. J'ai mis un sommeil de 0,01 entre chaque rangée pour le prouver.
L'exécution du script avec arg y vous montre des exemples de ce que votre fenêtre de terminal utilise pour positionner le curseur. J'ai codé en dur mes évasions dans l'écho. Le vôtre peut être différent. Pour la portabilité, vous devez utiliser tput pour générer les séquences dynamiquement. Pour les performances, vous devez obtenir toutes les séquences de tput dont vous aurez besoin pour votre application à l'avance et les stocker dans le Shell. De plus, une fois que le texte fixe est en place une fois, changez simplement les parties variables.
Notez que les positions d'écran commencent à (0, 0) dans les arguments tput. De plus, les zéros non significatifs dans les commandes d'écran sont interprétés comme octaux, c'est pourquoi je reformate le numéro de ligne visible avec printf. Il est également poli de déplacer le curseur (comme à (0,0)) après la mise à jour.
#! /bin/bash
#.. See what a CUrsor Position is on the current terminal.
[[ "${1}" == y ]] && {
for r in {0..19}; do
tput cup ${r} 15 | od -An -t ax1
done
exit
}
tput clear
while sleep 1; do
for k in {1..50}; do
sleep 0.01
RW=$( printf '%.2d' ${k} )
TS=$(date "+%Y-%m-%d %H:%M:%S.%N")
echo -n -e "\e[${k};1H${RW} ${TS}"
done
echo -n -e "\e[52;1H"
done
Après l'expiration du sommeil, faites écho à un retour arrière et réaffichez une valeur. Cela suppose que vous êtes sur un terminal qui peut afficher les codes d'échappement, la largeur et les lignes du terminal, mais cela fonctionne comme un coup rapide. Exemple: Afficher Spinner en attendant la fin d'un processus
Vous pouvez configurer une boucle dans bash - la construction est while true; do ....; done
où ....
est vos commandes. Vous auriez besoin de Ctrl+C pour l'arrêter.
Vous devez vous endormir, sinon il vous suffira de crier et de manger tout votre temps processeur. Les secondes pour dormir sont un compromis entre obtenir des chiffres actuels et avoir trop de sortie.
Si vous formatez la largeur de sortie à travers l'écran en colonnes fixes (utilisez la commande printf), il sera plus facile de voir les variations.
J'enverrais probablement la sortie de tout cela dans un fichier (redirection après le "fait"), afin que vous puissiez l'examiner à votre guise par la suite, peut-être même le représenter graphiquement ou faire des statistiques. Vous pouvez exécuter un tail -f
commande dans une autre fenêtre, qui vous montrera les dernières données ajoutées au fichier afin que vous puissiez les voir en temps réel.
Vous pouvez également placer une commande date
dans la boucle pour horodater chaque ligne, au cas où les intervalles entre les données sont importants.
Postez à nouveau si l'un de ces éléments a besoin de plus de viande sur les os.