moins file1 file2 | chat - pourquoi ça marche?

21

Lorsque j'utilise, less file1 file2j'obtiens les deux fichiers affichés dans le "visualiseur de mémoire tampon moins", mais less file1 file2 | catj'imprime le contenu des deux fichiers ajoutés à stdout. Comment sait-il moins s'il doit afficher "moins de visionneuse de tampon" ou produire une sortie vers stdout pour une prochaine commande? Quel mécanisme est utilisé pour ce faire?

tfh
la source

Réponses:

30

lessimprime le texte sur la sortie standard. stdout va

  • à un terminal (/ dev / tty?) et ouvre la visionneuse de tampon par défaut
  • à travers un tuyau lors de son acheminement vers un autre programme en utilisant | ( less text | cut -d: -f1)
  • vers un fichier lors de sa redirection avec> ( less text > tmp)

Il existe une fonction C appelée "isa tty " qui vérifie si la sortie va vers un tty (moins 4.81, main.c, ligne 112). Si c'est le cas, il utilise la visionneuse de tampon, sinon il se comporte comme cat.

En bash, vous pouvez utiliser test (voir man test)

  • -t FD descripteur de fichier FD est ouvert sur un terminal
  • -p FILE existe et est un canal nommé

Exemple:

[[ -t 1 ]] && \
    echo 'STDOUT is attached to TTY'

[[ -p /dev/stdout ]] && \
    echo 'STDOUT is attached to a pipe'

[[ ! -t 1 && ! -p /dev/stdout ]] && \
    echo 'STDOUT is attached to a redirection'
Michael D.
la source
1
@tfh Si STDOUT n'est pas attaché à un tuyau ou à une redirection, il est correct qu'ils n'impriment pas que STDOUT est attaché à un tuyau ou à une redirection. Mettez les trois dans un script. Appel bash script.sh, bash script.sh | cat, bash script.sh > fileet voir ce que la sortie que vous obtenez.
hvd
1
stdoutn'est pas quelque chose qui peut être "écrit dans un fichier". C'est quelque chose que vous devez write() faire . lessn'a rien à faire différemment selon que sa sortie est un fichier, un tube, une socket ou un bloc, ou autre. Il importe seulement que ce ne soit pas un tty, donc il se comporte juste comme cat. (Je suppose que vous le saviez et que vous avez juste choisi les mauvais mots pour l'expliquer, mais je pensais le signaler aux autres lecteurs).
Peter Cordes
Donc, vous voulez dire que c'est la tâche de moins de se comporter comme cat dans ma question spécifique - ou plus généralement: de se comporter comme la prochaine commande dans un pipeline. D'après ce que j'ai compris, je ne peux pas supposer que le même comportement exact est également implémenté dans un outil différent.
TFH
@tfh: Non, lessne "comprend" pas la catprochaine étape. Il se comporte simplement comme catquoi que ce soit ensuite, si c'est standard, ce n'est pas un tty.
Peter Cordes
@MichaelD .: merci, corrigé ma réponse. J'ai juste deviné que lesscela irait de l'avant et utiliser un TCGETS pour obtenir les dimensions du terminal ou découvrir que ce n'était pas un tty, mais apparemment, je me suis trompé.
Peter Cordes
6

lessvérifie s'il stdouts'agit d'un terminal et se comporte comme cats'il ne l'était pas (copie stdin vers stdout jusqu'à EOF).

Cette fonctionnalité vous permet d'écrire des scripts ou des programmes qui envoient toujours leur sortie (par exemple la --helpsortie) lesstout en permettant une redirection facile vers un fichier. Il serait nul si some_command --fullhelp > help.txton attendait toujours la barre d'espace sur stdin pour parcourir le texte, ou quelque chose. Certaines commandes (par exemple man) vérifient que leur propre sortie pour décider d'envoyer ou non leur sortie via un pager. Si vous exécutez man ls > ls.txt, il n'invoque jamais votre $PAGER.

lessLe comportement de chat est pratique si vous oubliez de le modifier à partir d'une ligne unique lorsque vous ajoutez plus d'étapes à un pipeline.


lessdoit comprendre les dimensions du terminal (taille de l'écran, pour savoir combien de lignes afficher en même temps). Celui ioctl(2)qu'il utilise stdoutretournerait ENOTTY sur un non-terminal, il ne peut donc pas éviter de gérer le cas non-terminal de toute façon. lessutilise en fait isatty(3)avant de vérifier les dimensions du terminal, mais isattyfonctionne en essayant un ioctl uniquement tty et en vérifiant l'absence d'erreur.

Même un simple pager comme more(1)(au moins la version util-linux) a cette fonctionnalité, car c'est probablement le comportement sain le plus simple à implémenter dans ce cas.


Notez que lorsque vous redirigez quelque chose dans less (par exemple grep foo bar.txt | less), il ne faut ouvrir /dev/ttypour la saisie du clavier. (Vous pouvez le voir faire cela avec echo foo | strace less).

Peter Cordes
la source