У меня есть массив путей:
paths=(
/foo/exists1
/foo/exists2
/foo/missing1
)
Чтобы найти недостающие:
ls "${paths[@]}" 1>/dev/null
Показывает:
ls: нет доступа к '/ foo / missing1': нет такого файла или каталога
Хорошо. Теперь я хочу убрать это:
ls "${paths[@]}" 1>/dev/null | sed 's/ls: cannot access //' | sed 's/: No such file or directory//''
Но я получаю:
ls: нет доступа к '/ foo / missing1': нет такого файла или каталога
/ foo / существует1
/ foo / существует2
Так что sed
не работает, также отображаются существующие файлы.
Почему это происходит (почему игнорируется 1>/dev/null
), и как мне это исправить?
У тебя есть уже обнаружено непосредственная причина того, что ваш код не сделал того, что вы ожидали: ошибки ls
сообщаются в stderr (как предложено POSIX), который не воспринимается как входной поток. Таким образом, вы получили смесь нормального вывода (который прошел без изменений вашим sed
операторы) и stderr (который их обошел). Я не знаю почему твой ls
выход менялся между звонками; перенаправление stdout в / dev / null должно иметь эффект удаления всех "нормальных" (существующих путей) из вывода. Исправление для этого не впихнуть stderr в stdout.
Постобработка вывода из ls
- опасная идея, если вам нужен надежный сценарий. Одна хорошая статья по этой теме: "Почему вам не следует анализировать вывод ls (1)", доступный на сайте wooledge.org. Один подробный вопрос / ответ на сайте Unix & Linux касается некоторых проблем: Зачем не разбирать ls
(а что делать вместо этого)?. В результате имена файлов UNIX могут содержать практически любой символ, включая пробелы, табуляции, новые строки, одинарные кавычки, двойные кавычки, экранированные одинарные кавычки и т. Д.! В качестве быстрых примеров рассмотрим каталоги с этими именами, все из которых совершенно законны:
mkdir "No such file"
)mkdir "ls: cannot access 'foo': No such file or directory"
)"каталог
с участием
встроенный
новые строки "(mkdir $'directory\nwith\nembedded\newlines'
)
Первый - это невинный каталог, ошибочно захваченный (из stdout) grep
. Второй тоже был захвачен незаконно, но затем его исказили. совершенно другой путь - которые могут существовать, а могут и не существовать! -- посредством sed
заявления. Третий - это один из примеров того, что происходит, когда вы передаете вывод ls
в линейно-ориентированные программы; если каталог не существует, ls
скажет это более чем в одной строке, что, вероятно, привело к тому, что вы получили два отдельных sed
заявления!
Чтобы отличить «хорошие пути» - существующие и читаемые - от «плохих путей», я бы предложил перебирать массив и строить новые массивы для каждого.
for p in "${paths[@]}"
do
if [ -r "$p" ]
then
goodpaths+=("$p")
else
badpaths+=("$p")
fi
done
Затем вы можете делать все, что захотите, с каждым набором:
printf 'Good path: -->%s<--\n' "${goodpaths[@]}"
echo
printf 'Bad path: -->%s<--\n' "${badpaths[@]}"
Проблема оказалась очевидной ... ошибки идут в файловый дескриптор 2, а не на стандартный вывод.
Так надо перенаправить 2
к 1
затем grep:
paths=(
/foo/exists1
/foo/exists2
/foo/missing1
)
ls "${paths[@]}" 2>&1 \
| grep 'No such file' \
| sed 's/ls: cannot access '\''//' \
| sed 's/'\'': No such file or directory//'