Již jste zjistili bezprostřední důvod, proč váš kód nedělal to, co jste očekávali:chyby z ls
jsou hlášeny do stderr (jak navrhuje POSIX), který není zachycen jako vstup roura. Získali jste tedy směs normálního výstupu (který prošel beze změny vaším sed
příkazy) a stderr (který je obešel). Nevím, proč máte ls
výstup se změnil mezi hovory; přesměrování stdout na /dev/null by mělo mít za následek odstranění všech "normálních" (existujících cest) z výstupu. Oprava tohoto problému není strčit stderr do stdout.
Následné zpracování výstupu z ls
je nebezpečný nápad, pokud chcete spolehlivý skript. Jeden dobrý článek na toto téma je „Proč byste neměli analyzovat výstup ls(1)“, dostupný na webu wooledge.org. Jedna hloubková otázka/odpověď na webu Unix &Linux se zabývá některými problémy:Proč ne analyzovat ls
(a co dělat místo toho)?. Výsledkem je, že názvy souborů UNIX mohou obsahovat téměř jakýkoli znak, včetně mezer, tabulátorů, nových řádků, jednoduchých uvozovek, dvojitých uvozovek, uvozovek s uvozovkami atd.! Pro několik rychlých příkladů zvažte adresáře s těmito názvy, z nichž všechny jsou naprosto legální:
- "Žádný takový soubor" (
mkdir "No such file"
) - "ls:nemůže získat přístup k 'foo':Žádný takový soubor nebo adresář" (
mkdir "ls: cannot access 'foo': No such file or directory"
) -
"adresář
s
vložené
nové řádky" (
mkdir $'directory\nwith\nembedded\newlines'
)
První je nevinný adresář, který je nesprávně zachycen (ze stdout) grep
. Druhá je také neprávem zachycena, ale pak dále zmačkaná do úplně jiné cesty -- který může a nemusí existovat! -- podle sed
prohlášení. Třetí je jeden příklad toho, co se stane, když předáte výstup ls
do linkově orientovaných programů; pokud adresář neexistuje, ls
řekne to na více než jednom řádku, což je pravděpodobně způsob, jakým jste skončili se dvěma samostatnými sed
prohlášení!
Abych odlišil „dobré cesty“ – ty, které existují a jsou čitelné – od „špatných cest“, navrhoval bych zacyklení pole a vytvoření nových polí pro každou z nich.
for p in "${paths[@]}"
do
if [ -r "$p" ]
then
goodpaths+=("$p")
else
badpaths+=("$p")
fi
done
S každou sadou si pak můžete dělat, co chcete:
printf 'Good path: -->%s<--\n' "${goodpaths[@]}"
echo
printf 'Bad path: -->%s<--\n' "${badpaths[@]}"