Hai già scoperto il motivo immediato per cui il tuo codice non ha funzionato come previsto:errori da ls
vengono segnalati a stderr (come suggerito da POSIX), che non viene catturato come input dalla pipe. Hai quindi ottenuto un misto di output normale (che è passato invariato dal tuo sed
statement) e stderr (che li ha aggirati). Non so perché il tuo ls
uscita cambiata tra le chiamate; reindirizzare stdout a /dev/null dovrebbe avere l'effetto di rimuovere tutti i "normali" (percorsi esistenti) dall'output. La soluzione per questo non per spingere stderr in stdout, però.
Post-elaborazione dell'output da ls
è un'idea pericolosa se vuoi uno script affidabile. Un buon articolo sull'argomento è "Perché non dovresti analizzare l'output di ls(1)", disponibile sul sito wooledge.org. Un'approfondita domanda/risposta sul sito Unix &Linux affronta alcuni dei problemi:Perché no analizza ls
(e cosa fare invece)?. Il risultato è che i nomi di file UNIX possono contenere quasi tutti i caratteri, inclusi spazi, tabulazioni, newline, virgolette singole, virgolette doppie, virgolette singole sfuggite, ecc.! Per alcuni rapidi esempi, considera le directory con questi nomi, che sono tutte perfettamente legali:
- "Nessun file simile" (
mkdir "No such file"
) - "ls:impossibile accedere a 'foo':file o directory non presenti" (
mkdir "ls: cannot access 'foo': No such file or directory"
) -
"cartella
con
integrato
newline" (
mkdir $'directory\nwith\nembedded\newlines'
)
La prima è una directory innocente catturata erroneamente (dallo stdout) dal grep
. Anche il secondo viene catturato erroneamente, ma poi ulteriormente mutilato in un percorso completamente diverso -- che può o non può esistere! -- dal sed
dichiarazioni. Il terzo è un esempio di ciò che accade quando passi l'output di ls
in programmi orientati alla linea; se la directory non esiste, ls
lo dirà su più di una riga, che è probabilmente il motivo per cui sei finito con due sed
separati affermazioni!
Per distinguere i "percorsi validi" (quelli che esistono e sono leggibili) dai "percorsi sbagliati", suggerirei di eseguire un ciclo sull'array e di creare nuovi array di ciascuno.
for p in "${paths[@]}"
do
if [ -r "$p" ]
then
goodpaths+=("$p")
else
badpaths+=("$p")
fi
done
Puoi quindi fare quello che vuoi con ogni set:
printf 'Good path: -->%s<--\n' "${goodpaths[@]}"
echo
printf 'Bad path: -->%s<--\n' "${badpaths[@]}"