(Так как алгоритмы только для оболочки оказались значительно медленнее, чем внешние инструменты, я просто удалил любые ссылки на них. Исходные данные могли бы быть интересными все же.)
Данные тестирования:
Prepare to remove role foo
Delete Successful
Prepare to remove role bar
Failed to delete role bar: 1
Prepare to remove policy baz
Delete Successful
Prepare to remove role ban
Delete Successful
something
else
Prepare to remove role bay
Failed to delete role bar: 2
Prepare to remove role bat
Failed to delete role bar: 1
Сравнительный тест с данными тестирования выше повторил миллион раз (это составляет 306 МБ), лучше всего из трех чередованных выполнений, отсортированных путем увеличения real
время:
Тестовый код:
for index in {1..3}
do
for path in grep.sh awk.sh
do
echo "$path:"
time bash "$path"
echo
done
done
Система тестирования: Intel Core i7 3,07 ГГц с 6 ГБ RAM.
В вашем примере apt-get update
не выходил с ошибкой,
потому что считал проблемы предупреждениями, а не смертельно плохими.
Если есть действительно фатальная ошибка, то она выйдет со статусом ненулевого.
Одним из способов распознавания аномалий является проверка этих закономерностей в stderr
:
W:
- это предупреждения E:
являются ошибками Можно использовать нечто подобное, чтобы эмулировать сбой в случае совпадения вышеуказанных шаблонов, или код выхода самого apt-get update
ненулевой:
if ! { sudo apt-get update 2>&1 || echo E: update failed; } | grep -q '^[WE]:'; then
echo success
else
echo failure
fi
Обратите внимание на !
в if
.
Это потому, что grep
успешно выходит, если шаблон был совпаден,
то есть, если бы были ошибки.
Когда ошибок нет, сам grep grep
не будет работать.
Поэтому условием if
является отрицание кода выхода grep
.
Если вы хотите, чтобы apt-get out / err не был съеден (например, если запись в файл журнала), это может быть более простой альтернативой:
sudo apt-get update 2> & 1 | тройник /tmp/apt.err &&! grep -q '^ [WE]' /tmp/apt.err
Было бы неплохо, если бы это не оставило новый файл, который можно было удалить позже, но если мы, скажем, процесс заменим grep на тройник output кажется сложнее получить код выхода.
Я столкнулся с той же проблемой, и я хотел бы предложить другое решение, основанное на tee
(, например решение @user4122451 ), но не создает временный файл, а также дает сбой, если sudo apt-get update
возвращает ненулевой код выхода, отличный от -, без вывода некоторой строки W:
, E:
или Err:
:
exec {fd}>&2 # copy stderr to some unused fd
bash -o pipefail -c "sudo apt-get update -y -q 2>&1 | tee /dev/fd/$fd | ( ! grep -q -e '^Err:' -e '^[WE]:' )"
result=$?
exec {fd}>&- # close file descriptor
В частности, это решение основано на параметреset -o pipefail
bash (, гарантирующем, что конвейер возвращает значение самой правой команды для выхода с ненулевым -статусом, в противном случае — нулевым )и использует дополнительный пронумерованный файл. дескриптор (см. также этот ответ SO).
Если вам не нужно делать параметр pipefail
локальным, вы можете просто написать:
set -o pipefail
exec {fd}>&2 # copy stderr to some unused fd
sudo apt-get update -y -q 2>&1 | tee /dev/fd/$fd | ( ! grep -q -e '^Err:' -e '^[WE]:' )
result=$?
exec {fd}>&- # close file descriptor
Вы можете использовать специальную переменную $? чтобы проверить статус выхода вашей последней команды. Вы также можете сначала перенаправить вывод ошибок на стандартный вывод.
OUTPUT=`apt-get update 2>&1`
if [[ $? != 0 ]]; then
echo "$OUTPUT"
fi
Используйте этот параметр apt, чтобы превратить эти предупреждения в ошибки:
apt-get update -o APT::Update::Error-Mode=any
Вы также можете установить это в файлах конфигурации, если хотите.