ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
Distribution: Debian /Jessie/Stretch/Sid, Linux Mint DE
Posts: 5,195
Rep:
Bad coders make a mess out of the most structured language elements. Deeply nested loops and if statements can become nicely wound spaghetti, but still spaghetti.
Goto's certainly serve a purpose... if used with care.
Ever tried to write a function which has to be left immediately in multiple conditions, but with the execution of some statements, like closing a file or releasing a mutex? Without goto?
Well, Linus doesn't seem to agree entirely with you.
Goto is always considered bad style these days, when we have safer constructs like while, for, if-else, etc.
The problem is with the compiler or interpreter that generates code out of these constructs... they tend to generate too much redundant code. While GOTOs are considered fine at the assembly level, they are not encouraged when using higher-level languages...and these include shell scripts!! Shell interpreters are written in a higher-level language anyway...
If you think bash or csh (or other shells) aren't good enough for you, write another one that compiles (or interpretes) while-, or for-loop constructs that generates the least assembly (or binary) code.
This is probably the best way of using GOTOs, by writing a compiler (or assembler, interpreter, etc.) in assembly. There's a super elegant solution of using JMPs for 80x86.
Well, Linus doesn't seem to agree entirely with you.
I have a problem.
I have built a script which goes through many 'if' tests. About twenty of them. Some of them, about 12, exit, if they meet certain conditions.
The problem is that if the script just exits, it leaves the system in bad condition: devices mounted to wrong directories etc.
The script should run about ten lines of code while exiting.
How to do this without GOTO ?
In good old days before purist programmers condemned it, we used GOTO to make this easy in Basic and Fortran.
Use a 'trap' to run a cleanup routine before exiting:
Code:
## User cancelled at a 'sensitive' spot, so scold them!
trap_int() {
echo
echo $RED"*** OUCH!!! ***"$NORMAL
emergency_restore
exit
}
# emergency_restore
emergency_restore() {
echo "Please don't interrupt during installation!"
# do whatever fixups (unmounts, etc) here:
}
# set a trap like this in your code before running 'sensitive' code:
trap trap_int 2
# The above just traps -INT, but you can specify multiple signals to trap
As far as I know, you can't 'revoke' a trap, so if you only need it at certain places and not in others, you can use another 'dummy' trap which does nothing in order to cancel the one above.
Use a 'trap' to run a cleanup routine before exiting:...
Thank you. This 'trap' didn't help this time, but it cave me an idea.
Now I'm using a function 'quit', where I can write all the cleanup I need.
Using one variable to tell, if the calling test has gone err or is the system exiting normally.
The whole script is too large to be copied here, I'll publish it on my site, when it is more mature. Here is small pieces of it to show how:
This script calls the main script:
Code:
#-- Calling script--
MAKER=/home/bin/backup/make_snapshot.sh;
# Call the main script:
$MAKER;
if (( $? )); then {
$ECHO "make_snapshot.sh script has been run" >>$ERROR_FILE;
$CAT $ERROR_FILE | $SENDMAIL $RECEIVER;
} fi;
This script makes most of the work:
Code:
#--Piece from the beginning of the script--
#------- VARIABLES -----------
# Set ERR=1 for default:
ERR=1;
#------- FUNCTIONS -----------
function quit {
$UMOUNT $MOUNT_DEVICE;
if (( $? )); then {
$ECHO "(1) ERROR: UNmounting $SNAPSHOT_RW" >>$ERROR_FILE;;
# ERR=1; Not needed, default
} fi;
exit $ERR;
}
#------- The MILL ----------
# make sure we're running as root
if (( `$ID -u` != 0 )); then {
$ECHO "(2) ERROR: Must be root. Exiting." >>$ERROR_FILE;;
# ERR=1; Not needed, default
quit;
} fi;
# ERR is '1' by default, change it to '0' when everything is OK:
ERR=0; quit;
# That's all, folks !
Some might wonder, why the scripts live in /home/bin/Backup rather than /usr/bin or some 'normal' directory.
This is because I have a habit to have three HD:s in my servers: one for the system, another for the /home and the third, the largest for the /BACKUP. I move /root, /var/www to /home and so it is MUCH easier to update system, make backups and recover broken systems. It is enough to backup /home and /etc.
It is very near I could make the whole system disk RO.
Let's say you have a function which initialized a few pointers, but those are only needed in that function.
You have to return from the function in let's say 20 if statement.
You have 3 choices:
- Free the pointers in every statement before return. This is BAD. If you add a new pointer, you have to write 20 new line!
- Write a function that will be called by this function. Still not too good. Our code will be fulled with "func1_quit", "func2_quit", etc unneeded functions, which just makes it more unreadable and robust. (You are trying to understand a function, every time you see the ..._quit called, you have to find it in the code, then go back to our function)
- Write a goto that will jump to the end of the function where all the needed destruction statements are there+you will have only 1 return. This way the code will be the MOST readable of every cases. That's why the linux kernel developers are using this method.
The teachers are saying "Don't use goto" just to learn the procedural thinking well, because goto is just extends this practise, and doesn't replace it!
The evolution of a programmer in terms of goto looks like:
-Using goto a lot of places (where he shouldn't)->BAD
-He learnt the goto is bad, won't use it anymore->Better, but still far from professional
-He realizes that goto can be good too, and using it where it makes the code more readable and easily maintenable->It's a good start..
I am converting JCL to shell script (for a client) and need to simulate the IBM JCL RESTART command. I learnt to program in COBOL and PL/1 over 20 years ago and agree that using goto to create spaghetti is bad but goto can be a lifesaver too when used judiciously.
Yeah, me too. What about using REXX or ooREXX for your client then - AFAIR there exist labels and the SIGNAL instruction. There are free implementations of it for Linux.
Like I said in one of the posts above, I worked out a way to have restart steps. I did this in 2006/2007 and it all worked sweetly, like a charm, I even simulated GDGs is Korn shell with the ability to roll back and do batch reruns. I have already forgotten most of the details and moved on to newer adventures. Let me know if you have questions and I can try to help.
It is weird to see people still repeat the myth that GOTOs are bad. It all comes from a letter written by Edgar Dijkstra to the ACM way back in 1968. It was titled "Goto Considered Harmful". I think most people simply read the title and didn't bother reading the whole two pages.
He was an early proponent of structured programming, and while he disliked the excessive use of GOTOs he actually felt they have a rightful place in programming. Unfortunately the tendency of people to reduce complex, balanced messages into quick, memorable, one-line summaries meant that many came to wrongly dismiss GOTO as bad practise. This terrible error in judgement has meant that generations of programmers must write complex, impenetrable code to replace a single, simple GOTO when it would have been the most sensible solution.
I've never understood people's propensity for elevating random statements by "important" people into the status of religious doctrine, and then for others to repeat that doctrine without question. It is as if some master carpenter came to the personal belief that hammers and nails are bad and that they should be replaced by screws and glue. But the fact is that hammers and nails are the appropriate tool for certain jobs. Likewise the GOTO is the appropriate tool in a rich toolbox of programming techniques. We are made poorer by its denial.
Bash scripts could often be made much simpler, faster, and easier to read by judicious use of GOTO. It is a great pity that it was omitted.
Additional:
I just found an annotated version of Dijkstra's article that enables people to wade through his awful writing style. You will be able to truthfully say you're one of the few who actually read the damned thing. It is here: http://david.tribble.com/text/goto.html
The bad image of GOTOs was probably reinforced by the early BASICs which used line numbers and lacked WHILE-WEND or REPEAT-UNTIL statements. As a result, users of these languages had to make clumsy representations of those statements by using GOTO statements instead (ever tried programming the Commodore 64?)
Nicholas Wirth probably had the right idea. You can use GOTOs if you wish but you have to do extra work first by setting up and declaring labels before you can use them.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.