Skip to main content
added 509 characters in body
Source Link
meuh
  • 54.8k
  • 2
  • 70
  • 140

Personally, I would go for the nested if then, as it would be easier to read and maintain. However, if you have tons of nesting levels you could try something like this (I've prefixed with echo for testing):

#!/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 

I've kept the run and undo functions in the order of your example, but you could gain by putting them closer to each other:

run1(){ mount a x;} undo1(){ umount x;} run2(){ mount b y;} undo2(){ umount y;} run3(){ setup_thing;} undo3(){ cleanup_thing;} ... 

Instead of numbering the functions 1,2,3... you could name the run functions anything and list the names in the order you want. Add a consistent prefix for the undo function to make it easier:

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 

Or you could indeed use trap, but set it up just once with trap mytrap exit, and use a global variable to hold what to cleanup and just add to it at each step: clean="1 $clean". The function mytrap would then just go through the values in $clean.

Personally, I would go for the nested if then, as it would be easier to read and maintain. However, if you have tons of nesting levels you could try something like this (I've prefixed with echo for testing):

#!/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 

I've kept the run and undo functions in the order of your example, but you could gain by putting them closer to each other:

run1(){ mount a x;} undo1(){ umount x;} run2(){ mount b y;} undo2(){ umount y;} run3(){ setup_thing;} undo3(){ cleanup_thing;} ... 

Or you could indeed use trap, but set it up just once with trap mytrap exit, and use a global variable to hold what to cleanup and just add to it at each step: clean="1 $clean". The function mytrap would then just go through the values in $clean.

Personally, I would go for the nested if then, as it would be easier to read and maintain. However, if you have tons of nesting levels you could try something like this (I've prefixed with echo for testing):

#!/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 

I've kept the run and undo functions in the order of your example, but you could gain by putting them closer to each other:

run1(){ mount a x;} undo1(){ umount x;} run2(){ mount b y;} undo2(){ umount y;} run3(){ setup_thing;} undo3(){ cleanup_thing;} ... 

Instead of numbering the functions 1,2,3... you could name the run functions anything and list the names in the order you want. Add a consistent prefix for the undo function to make it easier:

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 

Or you could indeed use trap, but set it up just once with trap mytrap exit, and use a global variable to hold what to cleanup and just add to it at each step: clean="1 $clean". The function mytrap would then just go through the values in $clean.

Source Link
meuh
  • 54.8k
  • 2
  • 70
  • 140

Personally, I would go for the nested if then, as it would be easier to read and maintain. However, if you have tons of nesting levels you could try something like this (I've prefixed with echo for testing):

#!/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 

I've kept the run and undo functions in the order of your example, but you could gain by putting them closer to each other:

run1(){ mount a x;} undo1(){ umount x;} run2(){ mount b y;} undo2(){ umount y;} run3(){ setup_thing;} undo3(){ cleanup_thing;} ... 

Or you could indeed use trap, but set it up just once with trap mytrap exit, and use a global variable to hold what to cleanup and just add to it at each step: clean="1 $clean". The function mytrap would then just go through the values in $clean.