Предполагая, что ваш файл почтового ящика находится в формате mbox, вы можете использовать утилита formail
, которая поставляется с procmail, для запуска команды для каждого письма с параметром -s
, чтобы сообщить ему, что ввод - это почтовый ящик, а не просто отдельное письмо.Эта команда может быть procmail
, если вы хотите применить свои правила procmail, или любой другой командой, которая принимает почту на стандартный ввод и делает с ней все, что захочет.
formail -s procmail <Mboxrd && mv Mboxrd Mboxrd.done
Другой подход - загрузить почтовый ящик в Mutt и применить некоторые макросы. Это имеет то преимущество, что оно не зависит от формата почтового ящика, но имеет недостаток, заключающийся в том, что макросы mutt могут быть загадочными (хотя не обязательно более загадочными, чем правила procmail). Еще одно преимущество использования mutt заключается в том, что он может перемещать по одному письму за раз, поэтому, если оно прервано на полпути, оно может возобновиться с того места, где оно было остановлено.
Лично я бы выбрал вложенный if then
, так как его было бы легче читать и поддерживать. Однако, если у вас много уровней вложенности, вы можете попробовать что-то вроде этого (Я поставил префикс echo
для тестирования):
#!/bin/bash
run1(){ echo mount a x;}
run2(){ echo mount b y;}
run3(){ echo setup_thing;}
run4(){ echo mount c z;}
run5(){ echo do_something;}
undo5(){ :;}
undo4(){ echo umount z;}
undo3(){ echo cleanup_thing;}
undo2(){ echo umount y;}
undo1(){ echo umount x;}
for i in {1..5}
do run$i
code=$?
[ $code != 0 ] && break
done
let i=i-1
while [ $i -gt 0 ]
do undo$i
let i=i-1
done
exit $code
Я сохранил функции запуска и отмены в порядке вашего примера, но вы могли бы выиграть, разместив их ближе друг к другу:
run1(){ mount a x;}
undo1(){ umount x;}
run2(){ mount b y;}
undo2(){ umount y;}
run3(){ setup_thing;}
undo3(){ cleanup_thing;}
...
Вместо нумерации функций 1,2,3... вы можете назвать функции выполнения как угодно и перечислить имена в нужном вам порядке. Добавьте согласованный префикс для функции отмены, чтобы упростить ее :
.mnta(){... }
undomnta(){... }
mntb(){... }
undomntb(){... }
order='mnta mntb...' toundo=
for i in $order
do $i
code=$?
[ $code != 0 ] && break
toundo="undo$i $toundo"
done
for i in $toundo
do $i
done
Или вы действительно можете использовать trap
, но настроить его только один раз с помощью trap mytrap exit
и использовать глобальную переменную для хранения того, что нужно очистить, и просто добавлять к этому на каждом шагу:clean="1 $clean"
. Затем функция mytrap
будет просто перебирать значения в $clean
.
Обычно используется trap
для отмены всего, когда вы закончите. Он должен быть идемпотентным, т. е. он должен изящно завершиться ошибкой, если некоторые из шагов не могут быть выполнены.
#!/bin/bash
clean_up=false
errorhandler () {
umount z || true
$clean_up && cleanup_thing
umount y || true
umount x
}
trap errorhandler ERR EXIT
mount a x
mount b y
setup_thing
clean_up=true
mount c z
do_something
Обратите внимание, что ловушка также срабатывает на EXIT
, поэтому она также будет выполняться до нормального завершения сценария; так что вам вообще не нужно очищать явно.
Я полагаю, что сигнал ERR
псевдо -является расширением Bash. Так что это не будет работать в Ash/Dash/устаревшей оболочке Bourne и т. д.