Sie haben bereits den unmittelbaren Grund entdeckt, warum Ihr Code nicht das getan hat, was Sie erwartet haben:Fehler von ls
werden an stderr gemeldet (wie von POSIX vorgeschlagen), was nicht als Eingabe von der Pipe erfasst wird. Sie haben also eine Mischung aus normaler Ausgabe (die unverändert durch Ihren sed
gelaufen ist Anweisungen) und stderr (was sie umgangen hat). Ich weiß nicht, warum Ihr ls
Ausgabe zwischen Aufrufen geändert; Das Umleiten von stdout nach /dev/null sollte bewirken, dass alle "normalen" (vorhandenen Pfade) aus der Ausgabe entfernt werden. Die Lösung dafür ist nicht aber stderr in stdout zu schieben.
Nachbearbeitung der Ausgabe von ls
ist eine gefährliche Idee, wenn Sie ein zuverlässiges Skript wollen. Ein guter Artikel zu diesem Thema ist "Why you should't parse the output of ls(1)", verfügbar auf der Wooledge.org-Site. Eine ausführliche Frage/Antwort auf der Unix- und Linux-Site geht auf einige der Probleme ein:Warum nicht parse ls
(und was ist stattdessen zu tun)?. Das Ergebnis ist, dass UNIX-Dateinamen fast jedes Zeichen enthalten können, einschließlich Leerzeichen, Tabulatoren, Zeilenumbrüche, einfache Anführungszeichen, doppelte Anführungszeichen, einfache Anführungszeichen mit Escapezeichen usw.! Betrachten Sie für einige schnelle Beispiele Verzeichnisse mit diesen Namen, die alle vollkommen legal sind:
- "Keine solche Datei" (
mkdir "No such file"
) - "ls:kann nicht auf 'foo' zugreifen:Keine solche Datei oder Verzeichnis" (
mkdir "ls: cannot access 'foo': No such file or directory"
) -
"Verzeichnis
mit
eingebettet
Zeilenumbrüche" (
mkdir $'directory\nwith\nembedded\newlines'
)
Das erste ist ein unschuldiges Verzeichnis, das fälschlicherweise (von stdout) von grep
erfasst wird . Die zweite wird ebenfalls fälschlicherweise erfasst, aber dann weiter in einen völlig anderen Pfad zerfleischt -- die existieren kann oder nicht! -- durch den sed
Aussagen. Das dritte ist ein Beispiel dafür, was passiert, wenn Sie die Ausgabe von ls
übergeben in zeilenorientierte Programme; wenn das Verzeichnis nicht existiert, ls
wird dies in mehr als einer Zeile sagen, was wahrscheinlich dazu geführt hat, dass Sie zwei separate sed
erhalten haben Aussagen!
Um "gute Pfade" -- solche, die existieren und lesbar sind -- von "schlechten Pfaden" zu unterscheiden, würde ich vorschlagen, das Array zu durchlaufen und jeweils neue Arrays zu erstellen.
for p in "${paths[@]}"
do
if [ -r "$p" ]
then
goodpaths+=("$p")
else
badpaths+=("$p")
fi
done
Sie können dann mit jedem Satz machen, was Sie wollen:
printf 'Good path: -->%s<--\n' "${goodpaths[@]}"
echo
printf 'Bad path: -->%s<--\n' "${badpaths[@]}"