Lorsque j'utilise find
pour voir tous les fichiers pdf dans le /home
répertoire, je vois access denied
. Pour les éliminer, j'ai essayé:
find /home -iname "*.pdf" | grep -v "access denied"
Cependant, le résultat est le même. Comment puis-je me débarrasser de ces lignes?
command-line
bash
find
solfish
la source
la source
Réponses:
Ce que vous avez essayé n'a pas fonctionné car les
access denied
résultats sont des erreurs et envoyés sur STDERR au lieu de STDOUT qui est canaliségrep
.Vous pouvez éviter de voir ces erreurs en redirigeant uniquement STDERR
Ou, comme l'a fait remarquer David Foerster, nous pouvons clôturer plus succinctement STDERR
Cependant, je suppose que vous ne souhaitez en fait rechercher que votre maison plutôt que celle d'autres utilisateurs, alors peut-être que vous voulez vraiment
Si cela génère des erreurs, il peut y avoir des propriétés erronées dans votre configuration locale, que vous devriez étudier.
la source
sudo chown $USER: ~/.gvfs ~/.dbus
2>&-
. GNU find ne se terminera pas s'il essaie d'écrire des messages d'erreur dans un descripteur de fichier dysfonctionnel. Car les problèmes de propriétésudo chown -R $USER: ...
seraient plus efficaces en cas de fichiers supplémentaires qui ne sont pas détenus par$USER
.L'accès refusé est probablement imprimé
stderr
plutôt questdout
.Essaye ça:
Le
2>&1
redirige la sortie destderr
versstdout
, afin que celagrep -v
puisse faire son travail. (Par défaut,|
seuls les tuyauxstdout
et nonstderr
.)la source
2>&1
... Je ne suis pas un expert bash, donc si c'est incorrect alors veuillez le dire :)bash
dans Ubuntu l'a, sauf en mode POSIX . Je pense que c'est la meilleure solution - un fichier malicieusement nomméaccess denied
apparaîtra toujours.Vous voulez probablement dire "Autorisation refusée" - qui est ce qui
find
dans Ubuntu vous montre lorsque vous ne pouvez pas accéder à quelque chose en raison des autorisations de fichier - plutôt que "accès refusé".Une commande entièrement générale qui le fait correctement (et, en bonus, est portable sur d'autres * nix es, tant que le message d'erreur est le même) est:
(Habituellement, vous voulez transmettre des arguments à
find
ceux-ci avant la première redirection3>&1
.)Cependant, vous pourrez souvent utiliser quelque chose de plus simple. Par exemple, vous pouvez probablement utiliser la substitution de processus . Les détails suivent.
Les méthodes les plus courantes et leurs limites
Les deux approches typiques sont de jeter stderr (comme dans la réponse de Zanna ) ou de rediriger stderr vers stdout et de filtrer stdout (comme dans la réponse d'Android Dev ). Bien qu'elles présentent l'avantage d'être simples à écrire et constituent souvent des choix raisonnables, ces approches ne sont pas idéales.
La suppression de tout ce qui est envoyé à stderr , par exemple en le redirigeant vers le périphérique nul avec
2>/dev/null
ou en le fermant avec,2>&-
entraîne le risque de manquer des erreurs autres que "Autorisation refusée"."Autorisation refusée" est probablement l'erreur la plus courante lors de l'exécution
find
, mais elle est loin d'être la seule erreur possible, et si une autre se produit, vous voudrez peut-être la connaître. En particulier,find
signale "Aucun fichier ou répertoire" si aucun point de départ n'existe. Avec plusieurs points de départ,find
peut toujours renvoyer des résultats utiles et semble fonctionner. Par exemple, sia
etc
existe maisb
n'existe pas,find a b c -name x
affiche les résultats dansa
, puis "Aucun fichier ou répertoire" pourb
, puis les résultats dansc
.La combinaison de stdout et stderr ensemble dans stdout et la canalisation vers
grep
ou une autre commande pour le filtrer, comme avec2>&1 | grep ...
ou,|& grep ...
entraîne le risque de filtrer involontairement un fichier dont le nom contient le message filtré.Par exemple, si vous filtrez les lignes qui contiennent «Autorisation refusée», vous supprimerez également les résultats de recherche affichant des noms de fichiers tels que «Autorisation refusée messages.txt». Cela se produirait probablement par accident, mais il serait également possible de donner à un fichier un nom spécialement conçu pour contrecarrer vos recherches.
Le filtrage des flux combinés présente un autre problème, qui ne peut pas être atténué par un filtrage plus sélectif (comme
grep -vx 'find: .*: Permission denied'
sur le côté droit du tuyau). Certainesfind
actions, y compris l'-print
action qui est implicite lorsque vous ne spécifiez aucune action, déterminent comment sortir les noms de fichiers selon que stdout est ou non un terminal.?
imprimés à la place.grep
), vousfind
ne voyez plus de terminal. (Plus précisément, cela empêche sa sortie standard d'être un terminal.) Ensuite, des caractères étranges sont littéralement affichés. Mais si toute la commande sur le côté droit du tuyau consiste à (a) supprimer les lignes qui ressemblent à des messages "Autorisation refusée" et (b) imprimer ce qui reste, alors vous êtes toujours soumis au genre de manigances qui sontfind
le terminal la détection est destinée à empêcher.man find
pour plus d'informations, y compris le comportement de chacune des actions qui impriment les noms de fichiers. ( "De nombreuses actions de find entraînent l'impression de données qui sont sous le contrôle d'autres utilisateurs ..." ) Voir aussi les sections 3.3.2.1 , 3.3.2.2 et 3.3.2.3 du manuel de référence GNU Findutils .La discussion ci-dessus des noms de fichiers inhabituels concerne GNU find , qui est l'
find
implémentation dans les systèmes GNU / Linux, y compris Ubuntu.Laisser la sortie standard seule pendant le filtrage de l'erreur standard
Ce que vous vraiment voulez ici est de laisser stdout intact tandis que la tuyauterie stderr à
grep
. Malheureusement, il n'y a pas de syntaxe simple pour cela.|
tuyaux stdout, et certains shells (y comprisbash
) prennent|&
en charge le tuyau des deux flux - ou vous pouvez d'abord rediriger stderr vers stdout2>&1 |
, ce qui a le même effet. Mais les shells couramment utilisés ne fournissent pas de syntaxe pour canaliser stderr uniquement.Vous pouvez toujours le faire. C'est juste gênant. Une façon consiste à échanger stdout avec stderr , afin que les résultats de la recherche soient sur stderr et que les erreurs soient sur stdout, puis dirigez stdout vers
grep
pour filtrer:Habituellement, vous passerez des arguments à
find
, tels que des points de départ (les endroits à rechercher, qui sont généralement des répertoires) et des prédicats (tests et actions). Ceux-ci vont à la place deargs
ci - dessus.Cela fonctionne en introduisant un nouveau descripteur de fichier pour conserver l'un des deux flux standard que vous souhaitez échanger, en effectuant des redirections pour les échanger et en fermant le nouveau descripteur de fichier.
3>&1
redirige le descripteur de fichier 3 vers stdout, de sorte que lorsque stdout (descripteur de fichier 1) est ensuite redirigé, la stdout d'origine peut toujours être écrite facilement.1>&2
redirige stdout vers stderr. Étant donné que le descripteur de fichier 3 est toujours la sortie standard d'origine, il est toujours accessible.2>&3
redirige stderr vers le descripteur de fichier 3, qui est la sortie standard d'origine.3>&-
ferme le descripteur de fichier 3, qui n'est plus nécessaire.Cependant, cette méthode présente l'inconvénient que les résultats de la recherche sont envoyés à stderr et que les erreurs sont envoyées à stdout . Si vous exécutez cette commande directement dans un shell interactif et que vous ne redirigez pas ou ne redirigez plus la sortie, cela n'a pas vraiment d'importance. Sinon, cela pourrait être un problème. Si vous placez cette commande dans un script, puis que quelqu'un (peut-être vous, plus tard) redirige ou redirige sa sortie, elle ne se comporte pas comme prévu .
La solution consiste à échanger les flux une fois que vous avez terminé de filtrer la sortie . L'application des mêmes redirections indiquées ci-dessus sur le côté droit du pipeline ne permettra pas d'atteindre cet objectif, car
|
seuls les canaux stdout, de sorte que ce côté du pipeline ne reçoit que la sortie qui a été initialement envoyée à stderr (car les flux ont été échangés) et non l'original sortie standard. Au lieu de cela, vous pouvez utiliser(
)
pour exécuter la commande ci-dessus dans un sous-shell ( lié ), puis appliquer les redirections d'échange à cela:C'est le regroupement, pas spécifiquement le sous-shell, qui fait que cela fonctionne. Si vous préférez, vous pouvez utiliser
{
;}
:Une méthode moins lourde: la substitution de processus
Certains shells, y compris Bash sur les systèmes qui peuvent le prendre en charge (y compris les systèmes GNU / Linux comme Ubuntu), vous permettent d'effectuer une substitution de processus , ce qui vous permet d'exécuter une commande et de rediriger vers / depuis l'un de ses flux. Vous pouvez rediriger le
find
stderr de lagrep
commande vers une commande qui le filtre et redirigergrep
le stdout de cette commande vers stderr.Nous remercions Android Dev pour cette idée.
1>&2
. J'ai utilisé>&2
, ce qui est équivalent ( lié ). Utilisez ce que vous voulez.Bien qu'il
bash
supporte la substitution de processus,sh
Ubuntu l' estdash
, ce qui n'est pas le cas. Il vous donnera "Erreur de syntaxe: redirection inattendue" si vous essayez d'utiliser cette méthode, tandis que la méthode de permutation de stdout et stderr fonctionnera toujours. En outre, lors de l'bash
exécution en mode POSIX , la prise en charge de la substitution de processus est désactivée.Une situation où
bash
s'exécute en mode POSIX est lorsqu'elle est appelée commesh
1 . Par conséquent, sur un système d'exploitation comme Fedora oùbash
fournit/bin/sh
, ou si vous avez fait/bin/sh
pointer le lien symbolique versbash
vous sur Ubuntu, la substitution de processus ne fonctionne toujours pas dans unsh
script, sans commande préalable pour désactiver le mode POSIX. Votre meilleur pari, si vous souhaitez utiliser cette méthode dans un script, est de mettre#!/bin/bash
en haut au lieu de#!/bin/sh
, si vous ne l'êtes pas déjà.1 : Dans cette situation,
bash
active automatiquement le mode POSIX après avoir exécuté les commandes dans ses scripts de démarrage.Un exemple
Il est utile de pouvoir tester ces commandes. Pour ce faire, je crée un
tmp
sous - répertoire du répertoire en cours et je le remplis avec certains fichiers et répertoires, en retirant des autorisations à l'un d'eux pour déclencher une erreur "Autorisation refusée" dansfind
.L' un des répertoires qui est accessible comprend un fichier avec « Autorisation refusée » dans son nom. L'exécution
find
sans redirections ni canaux affiche ce fichier, mais affiche également l'erreur réelle "Autorisation refusée" pour un autre répertoire qui n'est pas accessible:Le fait de canaliser à la fois stdout et stderr vers
grep
et filtrer les lignes qui contiennent "Autorisation refusée" fait disparaître le message d'erreur mais masque également le résultat de la recherche pour le fichier avec cette phrase dans son nom:find 2>&1 | grep -Fv 'Permission denied'
est équivalent et produit la même sortie.Les méthodes indiquées ci-dessus pour filtrer "Autorisation refusée" uniquement à partir des messages d'erreur - et non des résultats de la recherche - ont réussi. Par exemple, voici la méthode où stdout et stderr sont échangés:
find args 2> >(grep -Fv 'Permission denied' >&2)
produit la même sortie.Vous pouvez déclencher un message d'erreur différent pour vous assurer que les lignes envoyées à stderr qui ne contiennent pas le texte "Autorisation refusée" sont toujours autorisées. Par exemple, ici j'ai couru
find
avec le répertoire courant (.
) comme point de départ, mais le répertoire inexistantfoo
comme autre:Vérifier que
find
la sortie standard est toujours un terminalNous pouvons également voir quelles commandes provoquent l'affichage littéral des caractères spéciaux, tels que les retours à la ligne. (Cela peut être fait séparément de la démonstration ci-dessus, et il n'est pas nécessaire qu'il se trouve dans le
tmp
répertoire.)Créez un fichier avec une nouvelle ligne dans son nom:
Habituellement, nous utilisons des répertoires comme points de départ
find
, mais les fichiers fonctionnent aussi:L'ajout de stdout à une autre commande entraîne la sortie littérale de la nouvelle ligne, créant la fausse impression de deux résultats de recherche distincts
abc
et dedef
. Nous pouvons le tester aveccat
:Rediriger juste stderr ne cause pas ce problème:
La fermeture non plus:
La tuyauterie à
grep
fait la cause du problème:(Le remplacement
|&
par2>&1 |
est équivalent et produit la même sortie.)L'échange de stdout et stderr et de la tuyauterie stdout ne cause pas le problème
find
- la stdout de devient stderr, qui n'est pas canalisée:Le regroupement de cette commande et l'échange des flux en arrière ne provoque pas le problème:
(La
{
;}
version produit la même sortie.)L'utilisation de la substitution de processus pour filtrer stderr ne cause pas non plus le problème:
la source