Comportement étrange de «ls -a | grep ^ \. ”

10

Je voulais lister le contenu d'un pwd et afficher uniquement le fichier commençant par un point. J'ai essayé ls -a | grep ^\.mais je ne peux pas comprendre pourquoi la sortie contient également les fichiers qui ne commencent pas par un point. Par exemple:

Pictures
.pip
.pki
.profile
projects
Public

Je sais que je peux réaliser ce que je veux avec ls -ld .*je suis juste curieux de ce comportement de grep que je ne peux pas expliquer.

ps-aux
la source
Pourquoi ne pas simplement ls -d .*lister tous les fichiers commençant par .?
Barmar
Attention: ne dirigez jamais la sortie de ls vers une autre commande. Utilisez plutôt find. Il y a beaucoup trop d'idéosyncrasies pour faire confiance. Voir: Pitfall 1 sur mywiki.wooledge.org/BashPitfalls - il a fait # 1! Le reste du site est super aussi.
Joe

Réponses:

20

Citez l'argument pour grep, ainsils -a | grep '^\.'

La raison en est que le shell le gère \.et le transforme en clair ., qui est grepensuite traité comme un caractère générique à un seul caractère. En cas de doute, citez toujours une chaîne qui contient (ou peut contenir) un caractère spécial pour le shell.

roaima
la source
Pourquoi le shell ignore-t-il \?
ps-aux
\ est une séquence d'échappement qui fait que le shell traite le caractère suivant comme un littéral. Dans ce cas grep ^\\., \\ est traité par le shell comme une simple barre oblique inverse et, à nouveau, le grep traite la barre oblique inverse unique suivie du point comme point littéral.
Avinash Raj
11

Vous devez mettre l'expression rationnelle grep entre guillemets.

ls -a | grep '^\.'

Remarque: N'analysez pas la sortie de la lscommande .

Avinash Raj
la source
Pourquoi est-il mauvais d'analyser la sortie de ls?
ps-aux
Depuis le lien: Dans son mode par défaut, si la sortie standard n'est pas un terminal, ls sépare les noms de fichiers par des retours à la ligne. C'est très bien jusqu'à ce que vous ayez un fichier avec une nouvelle ligne dans son nom.
Michael Durrant
@Michael Durrant: Je dirais qu'autoriser les sauts de ligne dans les noms de fichiers est un bogue système majeur.
jamesqf
@jamesqf - voir les nouvelles lignes dans les noms de fichiers (en particulier la réponse de sml ).
don_crissti
0

Si vous exécutez cmd ls -a | grep ^ \. alors grep ne considère pas "\" comme un caractère spécial et une signification de "." ne vous échappez pas.

Lorsque nous utilisons cmd ls -a | grep "^ \." alors grep considère "\" comme un caractère spécial et une signification de "." s'échappe. Cela vous donnera un résultat comme prévu.

Si vous souhaitez utiliser grep cmd sans guillemets, vous devez également échapper le caractère "\". Vous pouvez avoir un résultat attendu sans guillemets doubles en suivant la commande. ls -a | grep ^ \\.

Pour plus de détails sur la signification des caractères spéciaux dans Regex, reportez-vous au lien suivant. http://www.regular-expressions.info/quickstart.html

AVJ
la source