La commande ls fonctionne différemment selon le destinataire

12

Comment les commandes comme lssavent-elles quelle est leur sortie standard?

Il semble lsfonctionner différemment en fonction de la cible standard. Par exemple, si je le fais:

ls /home/matt/tmp 

le résultat est:

a.txt b.txt c.txt

Mais si je le fais

ls /home/matt/tmp | cat

le résultat est (ie nouvelle ligne par résultat):

a.txt
b.txt
c.txt

Le processus est passé un descripteur de fichier 1 pour stdout à droite? Comment détermine-t-il comment formater le résultat? Le descripteur de fichier révèle-t-il des informations?

Mâtt Frëëman
la source
Connexes unix.stackexchange.com/q/157285/4671 , unix.stackexchange.com/q/63108/4671 et probablement d'autres. Cela semble être un sujet populaire. Cela pourrait être une dupe de l'un d'eux.
Faheem Mitha

Réponses:

22

Le lsprogramme utilise isatty()pour savoir si fd 1 est un tty ou autre chose (pipe, fichier, etc…). De man 3 isatty:

int isatty(int fd);

DESCRIPTION
La isatty()fonction teste si fdun descripteur de fichier ouvert fait référence à un terminal


Mise à jour: ligne 1538 ls.cdepuis coreutils (révision git 43a987e1):

  if (isatty (STDOUT_FILENO))
    {
      format = many_per_line;
      /* See description of qmark_funny_chars, above.  */
      qmark_funny_chars = true;
    }

( many_per_linedevrait être auto-descriptif.)

Stéphane Gimenez
la source
8

Pas une réponse exacte mais une exemplification. Dans un script Bash , vous pouvez obtenir un effet similaire avec test/ [[« s -t:

-t FD True if FD is opened on a terminal.

L'utiliser comme ceci:

bash-4.2$ where() { [[ -t 1 ]] && echo 'my output goes to TTY' || echo 'my output is redirected'; }

bash-4.2$ where
my output goes to TTY

bash-4.2$ where | cat
my output is redirected

bash-4.2$ where > test.file
bash-4.2$ cat test.file
my output is redirected
homme au travail
la source
6

Depuis le ls(1) manuel d' OpenBSD :

Par défaut, ls répertorie une entrée par ligne vers la sortie standard; les exceptions concernent les terminaux ou lorsque les options -C, -m ou -x sont spécifiées.

Puis, plus tard:

-1 (Le chiffre numérique `` un ''.) Force la sortie à une entrée par ligne. Il s'agit de la valeur par défaut lorsque la sortie n'est pas vers un terminal.

[...]

- Forcer la sortie multi-colonnes; c'est la valeur par défaut lorsque la sortie est vers un terminal.

Kusalananda
la source
1

Vous pouvez exécuter lsdans un pseudo-terminal à l'aide de la script commande, diriger la sortie de lsvers une autre commande et obtenir le même format de sortie que s'il n'y avait pas de telle tuyauterie du flux stdout, c'est-à-dire comme si stdout était un terminal (tty).

Pour le sous - jacent isatty()mécanisme déjà signalé par Stéphane Gimenez voir ls.c .

ls -G /
ls -G / | cat
script -q /dev/null ls -G / | sed $'s/\r$//g' | cat

# tty | cat
# script -q /dev/null tty | cat
Ron
la source