7 votes

Faire apparaître la sortie de la commande sur une seule ligne

Est-il possible d'obtenir la sortie d'une commande - par exemple tar - pour écrire chaque ligne de sortie sur une seule ligne ?

Exemple d'utilisation :

tar -options -f dest source | [insert trickery here]

et la sortie montrerait chaque fichier en cours de traitement sans faire bouger l'écran : chaque sortie écrase la précédente. Est-ce faisable ?


Edit : nous semblons avoir une réponse fonctionnelle, mais allons plus loin : Et si on faisait la même chose, mais sur 5 lignes ? Vous voyez une sortie défilante qui n'affecte pas le reste du terminal. Je pense avoir trouvé une réponse, mais j'aimerais savoir ce que vous en pensez.

6voto

Dave Points 6972

Remplacez les nouvelles lignes par des retours de chariot.

 tar -options -f dest source | cut -b1-$(tput cols) | sed -u 'i\\o033[2K' | stdbuf -o0 tr '\n' '\r'; echo

Explication :

  • cut -b1-$(tput cols) : Tronque la sortie de tar si elle est plus longue que la largeur du terminal. Selon le peu de mouvement que vous souhaitez donner à votre terminal, ce n'est pas strictement nécessaire.

  • sed -u 'i\\o033[2K' : Insère un blanc de ligne au début de chaque ligne. Le site -u à sed le met en mode non tamponné. stdbuf -oL sed 'i\\033[2K' fonctionnerait tout aussi bien.

  • stdbuf -o0 tr '\n' '\r' : Utilisations tr pour échanger les nouvelles lignes avec les retours de chariot. Stdbuf s'assure que la sortie n'est pas tamponnée ; sans la balise \n sur un terminal à tampon de ligne, nous ne verrions aucune sortie.

  • echo : Sort une nouvelle ligne finale, de sorte que l'invite du terminal ne mange pas la dernière ligne.

Pour le problème que votre montage propose :

x=0; 
echo -e '\e[s'; 
tar -options -f dest source | while read line; do
      echo -en "\e[u" 
      if [ $x gt 0 ]; then echo -en "\e["$x"B"; fi;
      echo -en "\e[2K"
      echo -n $line | cut -b1-$(tput cols);
      let "x = ($x+1)%5";
done; echo;

N'hésitez pas à faire tenir tout cela sur une seule ligne. Cela donne en fait une solution alternative au problème original :

echo -e '\e[s'; tar -options -f dest source | while read line; do echo -en "\e[u\e2K"; echo -n $line | cut -b1-$(tput cols); done; echo

qui ne repose sur rien d'autre que les codes VT100.

4voto

mrj Points 693

Grâce à Dave/tripleee pour le mécanisme de base (remplacement des nouvelles lignes par des retours chariot), voici une version qui fonctionne réellement :

tar [opts] [args] | perl -e '$| = 1; while (<>) { s/\n/\r/; print; } print "\n"'

Réglage de $| permet à perl d'effectuer un vidage automatique après chaque print au lieu d'attendre les nouvelles lignes, et la nouvelle ligne de queue empêche votre dernière ligne de sortie d'être (partiellement) écrasée lorsque la commande se termine et que bash affiche une invite (c'est vraiment laid si c'est partiel, avec l'invite et le curseur suivis du reste de la ligne de sortie).

Ce serait bien d'accomplir cela avec tr mais je ne sais pas comment faire pour forcer l'accès à l'information. tr (ou tout autre standard similaire) pour vider la sortie d'état.

Edit : La version précédente est en fait moche, puisqu'elle n'efface pas le reste de la ligne après ce qui a été produit. Cela signifie que les lignes courtes qui suivent des lignes plus longues ont du texte restant. Cette solution (certes moche) corrige ce problème :

tar [opts] [args] | perl -e '$| = 1; $f = "%-" . `tput cols` . "s\r"; $f =~ s/\n//; while (<>) {s/\n//; printf $f, $_;} print "\n"'

(Vous pouvez également obtenir la largeur du terminal de manière plus perl, comme décrit ici Je ne voulais pas dépendre des modules CPAN.

4voto

Aaron McDaid Points 7761
tar -options -f dest source | cut -b1-$(tput cols) | perl -ne 's/^/\e[2K/; s/\n/\r/; print' ;echo

Explications :

  • | cut -b1-$(tput cols) Ceci afin de s'assurer que les colonnes ne sont pas trop larges.
  • (Dans perl -ne) s/^/\e[2K/ Ce code efface la ligne en cours, en effaçant les "anciennes" lignes. Cela devrait être au début de la ligne, afin de s'assurer que la dernière ligne de sortie est préservée et aussi pour s'assurer que nous ne supprimons pas une ligne jusqu'à ce que la ligne suivante soit disponible.
  • (Dans perl -ne) s/\n/\r/ Le site tr pourrait être utilisée ici, bien sûr. Mais une fois que j'ai commencé à utiliser perl, je suis resté fidèle à cette méthode.

PS Pour clarifier : il y a deux problèmes distincts de "largeur de ligne". Les deux doivent être résolus. (1) Nous devons dégager les lignes, afin qu'une ligne courte ne soit pas mélangée avec des lignes plus anciennes et plus longues. (2) Si une ligne est très longue, et est plus large que la largeur actuelle de la borne alors nous devons le couper.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X