13 votes

Pourquoi la commande pipe "l | grep "1"" donne le mauvais résultat?

Comme le montre l'image, j'utilise l pour obtenir le fichier dans le dossier actuel. Et ensuite, je veux obtenir le fichier avec le numéro 1, donc j'utilise le pipe et le grep.

Mais pourquoi les fichiers 2 et 22 apparaissent-ils ? Et qu'est-ce que le 1;34m ?

$ l
./ ../ 1 11 2 22
$ l | grep "1"
1;34m./ 1;32m../ 1 11 2 22

Mise à jour

J'ai déjà aliasé la commande l dans mon fichier zshrc.

 alias lsp="ls"
 alias ll='ls -alF'
 alias la='ls -A'
 alias l='ls -CF'
 alias ls="ls -alh --color"

Et voici le résultat de la commande type:

>$ type ls
ls is an alias for ls -alh --color

> $ type l
l is an alias for ls -CF

26voto

Sergiy Kolodyazhnyy Points 97292

Tout d'abord, ce que vous essayez de faire, l| grep est mauvais. Ne le faites pas. Voici pourquoi.

La commande l est en réalité un alias de ls -CF

$ type -a l
l is aliased to `ls -CF'

Par défaut dans le bash d'Ubuntu, ls est un alias de ls --color=auto. Comme l'a souligné steeldriver dans les commentaires, --color=auto est censé désactiver la colorisation. Dans votre cas spécifique, vous avez alias ls="ls -alh --color" et alias l="ls -CF", ce qui se traduit essentiellement par ls -alh --color -CF. Cette combinaison particulière d'options envoie toujours une sortie colorisée dans un pipe. Par exemple:

$ ls -alh --color -CF ~/TESTDIR | cat -A                                                                                 
^[[0m^[[01;34m.^[[0m/  ^[[01;34m..^[[0m/  1.txt  2.txt  3.txt  out.txt$

Remarquez comment les répertoires . et .. ont les mêmes séquences d'échappement.

Que signifie tout cela

Cela signifie que l affichera une liste colorisée des fichiers selon leur type. Le problème est que la colorisation se fait avec l'utilisation de séquences d'échappement. C'est ce que sont ces choses en 1:34m - ce sont des séquences d'échappement pour des couleurs spécifiques.

Le problème principal est que l'analyse de ls conduit souvent à des sorties incorrectes et à des désastres dans les scripts, simplement parce que ls permet des séquences d'échappement comme expliqué précédemment et d'autres caractères spéciaux. Consultez cet article pour plus d'informations: http://mywiki.wooledge.org/ParsingLs

Ce que vous devriez faire:

Utilisez la commande find :

bash-4.3$ ls
1.txt  2.txt  3.txt  out.txt
bash-4.3$ find . -maxdepth 1 -iname "*1*"
./1.txt

Vous pourriez faire quelque chose comme ceci avec un glob de shell et la commande de test moderne [[:

bash-4.3$ for file in * ;do if [[ "$file" =~ "1"  ]] ;then echo "$file" ;fi ; done
1.txt

Ou peut-être utiliser python, qui a de bien meilleures capacités de gestion des noms de fichiers que le bash seul

bash-4.3$ python -c 'import os;print [f for f in os.listdir(".") if "1" in f ]'
['1.txt']

S'il n'est pas nécessaire de traiter la sortie de ls, un simple globbing avec ls peut également faire l'affaire. (Rappelez-vous, cela ne sert qu'à visualiser la liste des fichiers, pas à la passer à un autre programme pour traiter le texte de sortie)

bash-4.3$ ls *1*
1.txt

6voto

WinEunuuchs2Unix Points 91128

Vos commandes l et ls sont configurées comme alias.

Lorsque vous les exécutez en envoyant la sortie à travers grep "1" (en utilisant |), chaque ligne d'écran où 1 apparaît est affichée, avec le 1 coloré en rouge.

Parce que les noms de fichier ., .., 2 et 22 apparaissent sur la même ligne d'écran, ils sont également affichés par grep mais n'apparaissent pas en rouge, ce qui montre les correspondances de grep.

Le :34m est une séquence d'échappement pour une couleur qui ne se peint pas correctement. Sur la base de votre question révisée avec la sortie de type -a l et type -a, il peut être reproduit dans mon système. Veuillez noter que vous devriez changer votre alias de --color à --color=auto:

Sortie en couleur

ls en couleur

1voto

pilko Points 111

Lors de votre essai, vous appeliez votre alias ls, d'où le bruit de couleur 1;34m et similaire qui provient de la coloration, et puisque le pipe | reçoit tout cela sur la même ligne, le grep correspond au fichier 1 de cette ligne et imprime donc cette ligne. C'est ce que vous voyez à l'écran.

Quand vous faites des choses comme ça, il est toujours bon de revenir à la commande système avec 1 résultat par ligne.

Pour se débarrasser des alias, il suffit de taper \ls, et d'utiliser l'option -1 pour imprimer les résultats séparés par des sauts de ligne.

$ \ls -1 | grep "1"
1
11

Remarque : la méthode du backslash fonctionne avec chaque commande, \commande appelle simplement la commande système sans alias.

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X