3
votes

Comment puis-je modifier la sortie d'un script Bash en attendant l'entrée de l'utilisateur?

Je veux créer un chronomètre dans Bash, avec une fonction de pause. Il devrait afficher un compteur incrémentiel, comme celui-ci , mais le met en pause lorsque j'appuie sur le "p" clé.

Comment dois-je mettre cela en œuvre? Si j'attends la saisie de l'utilisateur avec read , je ne peux pas actualiser le compteur à l'écran en même temps. Mettre le read dans une boucle, avec un timeout, est mon meilleur plan jusqu'à présent, mais ce n'est pas trivial d'utiliser un timeout de moins d'une seconde, ce dont j'aurais besoin ici. (Ce n'est pas pris en charge par read ou GNU timeout .) Les interruptions fonctionneraient, mais j'aimerais prendre en charge des clés arbitraires comme "p" et "x".

Existe-t-il un moyen raisonnablement simple d'y parvenir?


3 commentaires

Quelque chose avec un processus en arrière-plan pour mettre à jour le compteur, puis le tuer si vous obtenez l'entrée de l'utilisateur?


Pourquoi fais-tu ça? Quelles sont vos limites? Est-ce que cela doit être fait en bash? Bien sûr, cela peut être fait dans bash mais ce ne serait probablement pas aussi raisonnablement simple que dans d’autres langages.


@brunorey - Ma préférence est de savoir comment le faire dans Bash, mais j'envisagerais d'autres solutions.


3 Réponses :


0
votes

J'ai fait un changement dans le code que vous faites référence.

while read char;
do 
   if [ $char == "p" ]; then
       if [ -z $(cat /tmp/pause) ];then
           echo 1 > /tmp/pause
       else
           echo > /tmp/pause
       fi
       char=0 
   fi
done < /dev/stdin

Donc, ce que vous devez faire maintenant est un script shell qui attend le caractère "p" de stdin et écrit 1> / tmp / pause ou clean / tmp / pause pour mettre le chronomètre en pause ou fonctionner.

quelque chose comme:

...
while [ true ]; do
    if [ -z $(cat /tmp/pause) ]; then
        STOPWATCH=$(TZ=UTC datef $DATE_INPUT $DATE_FORMAT | ( [[ "$NANOS_SUPPORTED" ]] && sed 's/.\{7\}$//' || cat ) )
        printf "\r\e%s" $STOPWATCH
        sleep 0.03
    fi
done


0 commentaires

1
votes

Imprimer sur la console en attendant l'entrée de l'utilisateur
  1. Écrivez une fonction qui crée la sortie (exemple avec: compteur ou si vous aimez spin ).
  2. Ecrire une fonction à lire dans les commandes utilisateur ( readCommand )
  3. Appel des deux fonctions dans une boucle
  4. Définissez les délais d'expiration pour que les pressions sur les touches soient lues assez tôt. ( sleep .1 et read -t.1 )
function readCommand(){
   lastCommand=$1
   read -t.1 -n1 c;
   if [ "$c" = "p" ]
   then
     printf "\n\r"; 
     return 0
   fi
   if [ "$c" = "g" ]
   then
     printf "\n\r"; 
     return 1
   fi
  return $lastCommand
}

function spin(){
    for i in / - \\ \| ;
        do 
            printf "\r$i"; 
            sleep .1;
        done
}

function countUp(){
    currentCount=$1
    return `expr $currentCount + 1`
}

function counter(){
    countUp $count
    count=$?
    printf "\r$count"
    sleep .1;
}

command=1
count=0
while : 
do 
   if [[ $command == 1 ]]
   then
      counter
   fi
   readCommand $command
   command=$?
done 

Le compteur s'arrêtera si l'utilisateur appuie sur 'p' et continue si l'utilisateur appuie sur 'g' p>


0 commentaires

1
votes

Script simple avec descripteur de fichier et redirection d'entrée simple, ne laissant aucun fichier temporaire à nettoyer. L'attente se fait en utilisant le paramètre read -t.

Your name, Sir?
    2:12:17.153951623l
Sir Kamil, we exit

Exemple de sortie:

counter() {
        while ! read -t 0.05 -n1 _; do
                printf '\r\t%s' "$(date +%T.%N)"
        done
}

{
        IFS= read -p "Your name, Sir?"$'\n' -r name
        echo >&3
} 3> >(counter "$tmp")

echo "Sir $name, we exit"


2 commentaires

Cela semble très prometteur - malheureusement, ne fonctionne pas sur BSD (OSX), qui ne prend pas en charge les délais décimaux pour lecture . (Mais je n'ai pas spécifié OSX dans l'énoncé du problème.)


Hm, avez-vous timeout avec des nombres réels? Je pense que vous pouvez timeout 0.05 read -t -n1 _ ... et n'oubliez pas de vérifier l'état de reutrn.