Eliminazione delle righe "Accesso negato"


9

Quando uso findper vedere tutti i file pdf nella /homedirectory, sto vedendo access denied. Per eliminarli ho provato:

find /home -iname "*.pdf" | grep -v "access denied"

Tuttavia, il risultato è lo stesso. Come posso liberarmi di queste linee?


Risposte:


19

Quello che hai provato non ha funzionato perché l' access deniedoutput è costituito da errori e inviato su STDERR anziché su STDOUT a cui viene inviato il piping grep.

Puoi evitare di vedere quegli errori reindirizzando solo STDERR

find /home -iname "*.pdf" 2>/dev/null

O come ha commentato David Foerster, possiamo chiudere più brevemente STDERR

find /home -iname "*.pdf" 2>&-

Tuttavia, sospetto che in realtà tu voglia solo cercare la tua casa piuttosto che quella di altri utenti, quindi forse lo vuoi davvero

find ~ -iname "*.pdf"

Se ciò genera errori, potrebbero esserci delle proprietà errate nella tua configurazione locale, che dovresti esaminare.


3
Grrr, perché le persone mi picchiano sempre di 30 secondi? : \
You'reAGitForNotUsingGit

find: “/home/ihsan/.gvfs”: accesso negato find: “/home/ihsan/.dbus”: accesso negato, per il comando ~
solfish

c'è qualcosa che non va? Sì, desidero anche la home directory di altri utenti, anch'essa creata da me per testare
solfish,

2
@solfish Per quanto ne so, quei file dovrebbero essere di tua proprietà. Potresti volersudo chown $USER: ~/.gvfs ~/.dbus
Zanna il

1
Dovrebbe essere sufficiente chiudere Stderr 2>&-. GNU find non si interromperà se tenterà di scrivere messaggi di errore in un descrittore di file disfunzionale. Per i problemi di proprietà sudo chown -R $USER: ...sarebbe più efficace in caso di più file all'interno di cui non sono di proprietà $USER.
David Foerster,

8

L'accesso negato viene probabilmente stampato stderranziché anziché stdout.

Prova questo:

find /home -iname "*.pdf" 2>&1 | grep -v "access denied"

Il 2>&1reindirizza l'output stderra stdout, in modo che grep -vpossa fare il suo lavoro. (Per impostazione predefinita, |solo pipe stdoute non stderr.)


ma per questo 2> & 1 significa se esiste stderr inviare a stdout?
solfish

@solfish Yup, questo è esattamente il punto :)
SeiAGitForNotUsingGit

quello che non capisco è prima di "|" come uscita; abbiamo appena stderr giusto? e dopo "|" come input abbiamo ottenuto questo
solfish

@solfish Bene, ho riscontrato questo problema circa un anno e mezzo fa e sono stato in grado di risolverlo utilizzando un metodo diverso . Ma poi un commento sotto la mia risposta mi ha suggerito di usare semplicemente 2>&1... Non sono un esperto di bash, quindi se non è corretto, ti preghiamo di dirlo :)
SeiAGitForNotUsingGit

@AndroidDev Suggerisco di aggiungere quel metodo diverso a questa risposta come alternativa. La critica di Etan Reisner è stata che la sostituzione del processo non è portatile. Ma bashin Ubuntu ce l'ha, tranne che in modalità POSIX . Penso che sia la soluzione migliore : access deniedapparirà comunque un file maliziosamente chiamato .
Eliah Kagan,

4

Probabilmente intendi "Autorizzazione negata", che è ciò che findUbuntu ti mostra quando non puoi accedere a qualcosa a causa delle autorizzazioni dei file, piuttosto che "accesso negato".

Un comando completamente generale che lo fa correttamente (e, come bonus, è portatile per altri * nix es, purché il messaggio di errore sia lo stesso) è:

(find 3>&1 1>&2 2>&3 3>&- | grep -Fv 'Permission denied') 3>&1 1>&2 2>&3 3>&-

(Di solito si desidera passare alcuni argomenti a find. Questi vanno prima del primo reindirizzamento 3>&1.)

Tuttavia, spesso sarai in grado di utilizzare qualcosa di più semplice. Ad esempio, probabilmente è possibile utilizzare la sostituzione del processo . Seguono i dettagli.

I metodi più comuni e i loro limiti

I due approcci tipici sono di eliminare stderr (come nella risposta di Zanna ) o reindirizzare stderr a stdout e filtrare stdout (come nella risposta di Dev Android ). Sebbene abbiano il vantaggio di essere semplici da scrivere e spesso sono scelte ragionevoli, questi approcci non sono ideali.

Eliminare tutto ciò che viene inviato a stderr, ad esempio reindirizzandolo al dispositivo null con 2>/dev/nullo chiudendolo con, 2>&-comporta il rischio di errori mancanti diversi da "Autorizzazione negata".

"Autorizzazione negata" è probabilmente l'errore più comune riscontrato durante l'esecuzione find, ma è tutt'altro che l'unico errore possibile e, se si verifica un altro, è consigliabile conoscerlo. In particolare, findsegnala "Nessun file o directory" se non esiste un punto di partenza. Con più punti di partenza, findpuò comunque restituire alcuni risultati utili e sembrare funzionare. Per esempio, se ae cesistere, ma bnon lo fa, find a b c -name xstampe risultati in a, poi "No such file or directory" per b, poi i risultati a c.

Combinando stdout e stderr insieme in stdout e eseguendo il piping su grepo su qualche altro comando per filtrarlo, come con 2>&1 | grep ...o, si |& grep ...corre il rischio di filtrare involontariamente un file il cui nome contiene il messaggio filtrato.

Ad esempio, se si filtrano le righe che contengono "Autorizzazione negata", verranno eliminati anche i risultati della ricerca che mostrano nomi di file come "Autorizzazione negata messaggi.txt". Ciò probabilmente accadrà per caso, anche se sarebbe anche possibile che un file riceva un nome appositamente predisposto per contrastare le tue ricerche.

Il filtraggio dei flussi combinati ha un altro problema, che non può essere mitigato filtrando in modo più selettivo (ad esempio con grep -vx 'find: .*: Permission denied'sul lato destro del tubo). Alcune findazioni, inclusa l' -printazione implicita quando non si specifica alcuna azione, determinano come produrre i nomi dei file in base al fatto che stdout sia o meno un terminale.

  • Se non è un terminale, i nomi dei file vengono emessi così come sono anche se contengono strani caratteri come newline e caratteri di controllo che potrebbero cambiare il comportamento del tuo terminale. Se si tratta di un terminale, questi caratteri vengono soppressi e ?vengono invece stampati.
  • Questo è di solito quello che vuoi. Se hai intenzione di elaborare ulteriormente i nomi dei file, devono essere stampati letteralmente. Tuttavia, se si desidera visualizzarli, un nome file con una nuova riga potrebbe altrimenti imitare più nomi di file e un nome file con una sequenza di caratteri backspace potrebbe apparire con un nome diverso. Sono anche possibili altri problemi, come i nomi di file contenenti sequenze di escape che cambiano i colori nel terminale.
  • Ma il piping dei risultati della ricerca attraverso un altro comando (come grep) findnon fa più vedere un terminale. (Più precisamente, fa sì che il suo stdout non sia un terminale.) Quindi vengono emessi letteralmente strani caratteri. Ma se tutto il comando sul lato destro della pipe è (a) rimuovere le righe che sembrano messaggi "Autorizzazione negata" e (b) stampare ciò che rimane, allora sei ancora soggetto al tipo di shenanigans che findè il terminale il rilevamento ha lo scopo di prevenire.
  • Vedere la sezione FILENAMI INUSUALI di man findper ulteriori informazioni, incluso il comportamento di ciascuna delle azioni che stampano i nomi dei file. ( "Molte delle azioni di seguito troviamo nella stampa dei dati, che è sotto il controllo di altri utenti ..." ) vedi anche sezioni 3.3.2.1 , 3.3.2.2 e 3.3.2.3 del manuale di riferimento GNU Findutils .

La discussione sopra di nomi di file insoliti riguarda GNU find , che è l' findimplementazione in sistemi GNU / Linux incluso Ubuntu.

Lasciare da solo l'output standard durante il filtraggio dell'errore standard

Quello che veramente vuole qui è quello di lasciare stdout intatta mentre tubazioni stderr a grep. Sfortunatamente non esiste una sintassi semplice per questo. |pipe stdout e alcune shell (incluso bash) supportano il |&pipe di entrambi i flussi, oppure puoi reindirizzare prima stderr su stdout 2>&1 |, il che ha lo stesso effetto. Ma le shell comunemente usate non forniscono solo una sintassi per pipe stderr.

Puoi ancora farlo. È solo imbarazzante. Un modo è scambiare stdout con stderr , in modo che i risultati della ricerca siano su stderr e gli errori siano su stdout, quindi reindirizzare stdout a grepper filtrare:

find args 3>&1 1>&2 2>&3 3>&- | grep -Fv 'Permission denied'

Di solito passerai argomenti a find, come punti di partenza (i luoghi da cui cercare, che di solito sono directory) e predicati (test e azioni). Questi vanno al posto di argssopra.

Funziona introducendo un nuovo descrittore di file da conservare su uno dei due flussi standard che si desidera scambiare, eseguendo reindirizzamenti per scambiarli e chiudendo il nuovo descrittore di file.

  • Il descrittore di file 1 è stdout e 2 è stderr (e lo 0 non reindirizzato è stdin ). Ma puoi anche reindirizzare utilizzando altri descrittori di file. Questo può essere usato per aprire o mantenere aperto un file o dispositivo.
  • 3>&1 reindirizza il descrittore di file 3 su stdout, in modo che quando lo stdout (descrittore di file 1) viene successivamente reindirizzato, lo stdout originale può ancora essere scritto facilmente.
  • 1>&2reindirizza stdout a stderr. Poiché il descrittore di file 3 è ancora lo stdout originale, è ancora possibile accedervi.
  • 2>&3 reindirizza stderr al descrittore di file 3, che è lo stdout originale.
  • 3>&- chiude il descrittore di file 3, che non è più necessario.
  • Per ulteriori informazioni, vedere Come eseguire il pipe di stderr e non di stdout? e reindirizzamento IO - Scambiare stdout e stderr (Avanzato) e soprattutto reindirizzare solo stderr attraverso un filtro .

Tuttavia, questo metodo ha lo svantaggio che i risultati della ricerca vengono inviati a stderr e gli errori vengono inviati a stdout . Se stai eseguendo questo comando direttamente in una shell interattiva e non esegui il piping o il reindirizzamento dell'output, non importa. Altrimenti, potrebbe essere un problema. Se metti quel comando in uno script e poi qualcuno (forse tu, in seguito) reindirizza o reindirizza il suo output, non si comporta come previsto .

La soluzione è di scambiare i flussi dopo aver finito di filtrare l'output . L'applicazione degli stessi reindirizzamenti mostrati sopra sul lato destro della pipeline non raggiungerà questo obiettivo, perché |solo i tubi stdout, quindi quel lato della pipeline riceve solo l'output originariamente inviato a stderr (perché i flussi sono stati scambiati) e non l'originale uscita stdout. Invece, puoi usare ( )per eseguire il comando sopra in una sottostruttura ( correlata ), quindi applicare i reindirizzamenti di scambio a quello:

(find args 3>&1 1>&2 2>&3 3>&- | grep -Fv 'Permission denied') 3>&1 1>&2 2>&3 3>&-

È il raggruppamento, non specificamente la subshell, che fa funzionare tutto ciò. Se preferisci, puoi usare { ;}:

{ find args 3>&1 1>&2 2>&3 3>&- | grep -Fv 'Permission denied'; } 3>&1 1>&2 2>&3 3>&-

Un modo meno ingombrante: sostituzione del processo

Alcune shell, incluso Bash su sistemi in grado di supportarlo (inclusi sistemi GNU / Linux come Ubuntu), consentono di eseguire la sostituzione di processo , che consente di eseguire un comando e reindirizzare verso / da uno dei suoi flussi. È possibile reindirizzare lo findstderr del comando su un grepcomando che lo filtra e reindirizzare greplo stdout di quel comando su stderr.

find args 2> >(grep -Fv 'Permission denied' >&2)

Il merito va a Android Dev per questa idea.

Sebbene bash supporti la sostituzione dei processi, shin Ubuntu lo è dash. Se si tenta di utilizzare questo metodo, verrà visualizzato "Errore di sintassi: reindirizzamento imprevisto", mentre il metodo di scambio di stdout e stderr continuerà a funzionare. Inoltre, quando bashviene eseguito in modalità POSIX , il supporto per la sostituzione del processo è disattivato.

Una situazione in cui bashviene eseguita in modalità POSIX è quando viene invocato come sh1 . Pertanto, su un sistema operativo come Fedora dove bashfornisce /bin/sh, o se il /bin/shcollegamento simbolico è stato puntato bashsu Ubuntu, la sostituzione del processo non funziona ancora in uno shscript, senza un comando precedente per disattivare la modalità POSIX. La tua scommessa migliore, se vuoi usare questo metodo in uno script, è quella di metterti #!/bin/bash in cima invece che #!/bin/sh, se non lo sei già.

1 : in questa situazione, bashattiva automaticamente la modalità POSIX dopo aver eseguito i comandi nei suoi script di avvio.

Un esempio

È utile poter testare questi comandi. Per fare ciò, creo una tmpsottodirectory della directory corrente e la popolo con alcuni file e directory, togliendo le autorizzazioni da una di esse per attivare un errore "Autorizzazione negata" find.

mkdir tmp; cd tmp; mkdir a b c; touch w a/x 'a/Permission denied messages.txt' b/y c/z; chmod 0 b

Una delle directory che è accessibile include un file con "Permesso negato" nel suo nome. L'esecuzione findsenza reindirizzamenti o pipe mostra questo file, ma mostra anche l'errore "Autorizzazione negata" effettiva per un'altra directory non accessibile:

ek@Io:~/tmp$ find
.
./a
./a/Permission denied messages.txt
./a/x
./c
./c/z
./w
./b
find: ‘./b’: Permission denied

Piping sia su stdout che su stderr grepe filtrando le righe che contengono "Autorizzazione negata" fa sparire il messaggio di errore ma nasconde anche il risultato della ricerca per il file con quella frase nel suo nome:

ek@Io:~/tmp$ find |& grep -Fv 'Permission denied'
.
./a
./a/x
./c
./c/z
./w
./b

find 2>&1 | grep -Fv 'Permission denied' è equivalente e produce lo stesso output.

I metodi sopra indicati per filtrare "Autorizzazione negata" solo dai messaggi di errore e non dai risultati della ricerca hanno esito positivo. Ad esempio, ecco il metodo in cui vengono scambiati stdout e stderr:

ek@Io:~/tmp$ (find 3>&1 1>&2 2>&3 3>&- | grep -Fv 'Permission denied') 3>&1 1>&2 2>&3 3>&-
.
./a
./a/Permission denied messages.txt
./a/x
./c
./c/z
./w
./b

find args 2> >(grep -Fv 'Permission denied' >&2) produce lo stesso output.

È possibile attivare un messaggio di errore diverso per assicurarsi che le righe inviate a stderr che non contengono il testo "Autorizzazione negata" siano ancora consentite. Ad esempio, qui ho eseguito findcon la directory corrente ( .) come punto di partenza, ma la directory inesistente foocome un altro:

ek@Io:~/tmp$ (find . foo 3>&1 1>&2 2>&3 3>&- | grep -Fv 'Permission denied') 3>&1 1>&2 2>&3 3>&-
.
./a
./a/Permission denied messages.txt
./a/x
./c
./c/z
./w
./b
find: foo’: No such file or directory

Verificare che l find'output standard sia ancora un terminale

Possiamo anche vedere quali comandi causano la visualizzazione letterale di caratteri speciali, come le nuove righe. (Questo può essere fatto separatamente dalla dimostrazione sopra e non deve essere nella tmpdirectory.)

Crea un file con una nuova riga nel suo nome:

touch $'abc\ndef'

Di solito usiamo le directory come punti di partenza per find, ma anche i file funzionano:

$ find abc*
abc?def

Il piping di stdout a un altro comando provoca l'output letterale della nuova riga, creando la falsa impressione di due risultati di ricerca separati abce def. Possiamo provarlo con cat:

$ find abc* | cat
abc
def

Il reindirizzamento di solo stderr non causa questo problema:

$ find abc* 2>/dev/null
abc?def

Né chiuderlo:

$ find abc* 2>&-
abc?def

Tubazioni per grep fa causa il problema:

$ find abc* |& grep -Fv 'Permission denied'
abc
def

(La sostituzione |&con 2>&1 |è equivalente e produce lo stesso output.)

Scambiare stdout e stderr e piping stdout non causa il problema find: lo stdout diventa stderr, che non viene convogliato:

$ find abc* 3>&1 1>&2 2>&3 3>&- | grep -Fv 'Permission denied'
abc?def

Raggruppare quel comando e scambiare nuovamente i flussi non causa il problema:

$ (find abc* 3>&1 1>&2 2>&3 3>&- | grep -Fv 'Permission denied') 3>&1 1>&2 2>&3 3>&-
abc?def

(La { ;}versione produce lo stesso output.)

L'uso della sostituzione di processo per filtrare stderr non causa neanche il problema:

$ find abc* 2> >(grep -Fv 'Permission denied' >&2)
abc?def
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.