Anda telah menemukan alasan langsung kode Anda tidak melakukan apa yang Anda harapkan:kesalahan dari ls
dilaporkan ke stderr (seperti yang disarankan oleh POSIX), yang tidak ditangkap sebagai masukan oleh pipa. Oleh karena itu, Anda mendapatkan campuran keluaran normal (yang diteruskan tanpa perubahan oleh sed
Anda pernyataan) dan stderr (yang melewatinya). Saya tidak tahu mengapa ls
Anda keluaran berubah di antara panggilan; mengarahkan stdout ke /dev/null harus memiliki efek menghapus semua "normal" (jalur yang ada) dari output. Perbaikan untuk ini tidak untuk mendorong stderr ke stdout.
Pasca-pemrosesan output dari ls
adalah ide yang berbahaya jika Anda menginginkan skrip yang andal. Satu artikel bagus tentang topik ini adalah "Mengapa Anda tidak mengurai keluaran ls(1)", tersedia di situs wooledge.org. Satu T/J mendalam di situs Unix &Linux membahas beberapa masalah:Mengapa tidak parsing ls
(dan apa yang harus dilakukan sebagai gantinya)?. Hasilnya adalah bahwa nama file UNIX dapat berisi hampir semua karakter, termasuk spasi, tab, baris baru, tanda kutip tunggal, tanda kutip ganda, tanda kutip tunggal yang lolos, dll! Untuk beberapa contoh singkat, pertimbangkan direktori dengan nama berikut, yang semuanya legal:
- "Tidak ada file seperti itu" (
mkdir "No such file"
) - "ls:tidak dapat mengakses 'foo':Tidak ada file atau direktori seperti itu" (
mkdir "ls: cannot access 'foo': No such file or directory"
) -
"direktori
dengan
tertanam
baris baru" (
mkdir $'directory\nwith\nembedded\newlines'
)
Yang pertama adalah direktori tidak bersalah yang ditangkap secara salah (dari stdout) oleh grep
. Yang kedua juga ditangkap secara salah, tetapi kemudian dirusak lebih lanjut menjadi jalur yang sama sekali berbeda -- yang mungkin ada atau tidak ada! -- oleh sed
pernyataan. Yang ketiga adalah salah satu contoh dari apa yang terjadi ketika Anda meneruskan output dari ls
ke dalam program berorientasi garis; jika direktori tidak ada, ls
akan mengatakannya lebih dari satu baris, yang mungkin merupakan cara Anda mendapatkan dua sed
terpisah pernyataan!
Untuk membedakan "jalur yang baik" -- yang ada dan dapat dibaca -- dari "jalur yang buruk", saya menyarankan untuk mengulang larik dan membuat larik baru dari masing-masing.
for p in "${paths[@]}"
do
if [ -r "$p" ]
then
goodpaths+=("$p")
else
badpaths+=("$p")
fi
done
Anda kemudian dapat melakukan apa pun yang Anda suka dengan setiap set:
printf 'Good path: -->%s<--\n' "${goodpaths[@]}"
echo
printf 'Bad path: -->%s<--\n' "${badpaths[@]}"