Linux - SoftwareThis forum is for Software issues.
Having a problem installing a new program? Want to know which application is best for the job? Post your question in this forum.
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.
Based upon some excellent advice from members of this forum I am redesigning a script which has gotten a little to complicated. Most of the code will be broken into functions and only the main flow control logic will be in the "main" part of the script. It is already looking much more manageable. However...
I have been playing with some simple scripts and functions to get my head wrapped around how bash handles functions. From what I am seeing I must define my function FIRST and then call the function. I will have a situation where function3 may need to call function5. Does this mean I must define function3 before funtion3 and all functions before I code the control loops and if statements? That seems contrary to "top down" programming. Sort of inside out programming
In other languages and environments I could place functions, especially utility type functions, in a separate file and then "assimilate" that file into the program at run time in an interpreted environment or at compile/pseudo-compile time. I suspect there is a way to handle this in bash. If I source the file containing the functions from within the main script, will all the functions be available in the main script?
By definition the function declaration must proceed the first call to it but technically your calling function 3 from the "main" part of the script so function order should not matter.
As far as I know it is possible to put functions in a separate file and add a source statement as the first line (i.e. after the shebang...)
I put a test function in a file and sourced it from my script. The function was available. I have not tried putting multiple functions in the sourced file and trying to call them from each other and "out of order." I have been busy chopping my BIG script into bite size functions. I wish I had started that way but it was only a small script to start
You can indeed put multiple fns in a separate file and call them.
The 'order' thing is because bash (& *nix shells generally) are interpreters, not compilers, so it has to have read the code before it can use it.
This is why the 'main' part of a script with fns needs to be at the bottom, so the shell has 'seen' (ie read) all the code it might use before it tries to use it.
The order of the fns between each other is not important.
I had sort of figured that. With xBase, at least the later iterations such as FoxPro, each ".prg" (plain text code) file was pseudo compiled when called. This allowed me to put my functions at the bottom. Now that I think about it I am not sure when that feature started. I don't think dBase II or dBase III had it. Perhaps it was FoxBase+.
I am testing the functions which I have extracted from my bg VPN managing script by placing them in a file, sourcing that file from a test script. So far so good.
I am testing the functions which I have extracted from my bg VPN managing script by placing them in a file, sourcing that file from a test script. So far so good.
For what it's worth, that's what I'd do. It helps to grow your experience learning about quirks like the differences of how the functions need to be defined first and that there's no equivalent of an external reference that is only a prototype, instead it has to be the fully defined function. Or experimenting with how far you can extend these concepts.
With the size and scope of the code you're mentioning, I'd be surprised if you didn't have a few revisions of the concept. If you haven't thought about it as yet, perhaps do some, reach a stable point, save that, and then take on the higher challenges which you're thinking about, but aren't sure about as yet. Or you may discover that you wish to have certain groupings of functions logically in different files, or a cascade where you have a simple library for fundamental operations and then other files where you're doing specific functions for a certain script or scripts.
I've never written scripts of enough complexity, or had some very large library, so I've not had the occasion to split things up as much, but there have been times I've thought about it. Good luck with your progress!
First it would help if I could type. "my bg VPN script" should have been "my big VPN script" That said...
My original script has gone from version 0.1 to the current 1.4. The root cause of the issue is that ProtonVPN (and ProtonMail) treat Linux as the proverbial red headed step child - even though they are no doubt running it on the back end. They have a VPN command line tool which is not bad when used interactively but... I just want my LAN connected all the time.
I currently have a Raspberry Pi 3B+ single board computer serving as my gateway, router, firewall, DHCP, VPN sharing etc. box. As the ProtonVPN utility does not have a reconnect feature I built a script to check every couple of seconds and if the VPN dropped then reconnect. The script is run as a systemctl service. Since then I have been adding code to trap various errors and strange conditions. I am at about 98% success. Sometimes, however, the VPN will die for no apparent reason that I cannot restart it. I have created another "crow bar" script which is run by cron every 5 minutes. It executes the ProtonVPN tool with the --status option and examines the result. If the VPN is not running it puts the proverbial crow bar across the power terminal and reboots the Pi. Sort of a last resort check. Perhaps I will convert that check into a function and include it in the main script.
quirks - that does not begin to describe it. I have 7 functions in my functions file. I have successfully run each of them from my test script. I added two more function to the function file. When I try to call them I get "command not found", I copied the first 7 functions to a separate file for archival process and deleted them from the function file. The two new functions now work. Is there a limit to how many functions I can source or include in a script?
Well, it gets even better. I just copied the 7 working functions to the END of the functions file. The last 2 functions work just fine. And the 2 new functions at the top of the file work fine. The functions are NOT calling each other.
I am editing the files with xed - the default text editor on Linux Mint Mate. Perhaps I need to examine the functions file with a hex editor. This is absurd.
Now that I have (I think) all of my functions coded I decided to play with a case structure or if then elif then elif then fi construct. I decided the latter was a better fit. I put in all of my conditions and a function call after the first if then. I received an error on the first elif then. Apparently there MUST be some sort of command following an elif then. I now have a bunch of "echo hello" statements as I build the thing. Oh well.
I came across that fact in some reading. I have gotten beyond that point. I have my actual code in the if elsif structure and have broken it out as another function. Now I am playing with state management. Is my VPN connected? Is it desired that it be connected or not etc. By time I am done I will have to write myself some documentation for this thing
Well, sometimes it helps to put 'set -xv' in your code, it debugs it ie dumps to the stdout all the cmds as it parses them and as it runs them.
Very informative, if a bit chatty
To debug just a chunk of code
Code:
# debug on
set -xv
code
code
# debug off
set +xv
Also, (for each new fn) try writing it as just a basic fn with one line that says 'echo <fn name>' to start with, just to see if it's being called when you expect it.
Wow! That is neat. If only I could single step through the script. Still, I am sure this will come in handy. Especially as it can be turned on and off dynamically as the script executes. I could enable it only for a certain function which I am trying to sort out etc.
That said, I finally have the main script and a second file with 11 functions which I source in at the beginning of the main script. I have been running it in test for a while and have exercised, I think, all of the various permutations which it is supposed to handle. I will try it out in "production" on my gateway, firewall, DHCP, VPN sharing Raspberry Pi tomorrow. Then I have to complete the client side script which will post flag files to the Pi telling it to disconnect the VPN, connect to a specific exit server, connect to a random server from a list or just connect to the "fastest" server based on latency.
Of course there is always an emergent issue. My OLD Brother laser printer finally died. I have another one on order, due Thursday. It is twice as fast and was only $150 US. However, I fear that it may be a little prone to "phone home." As offered on Amazon it would contact Amazon and order toner when it was running low. I think not. I purchased it elsewhere but still... I need to figure out how to configure the firewall on the Pi from allowing the IP or MAC address for the printer from ever contacting the Internet. I have played with that before but never figured it out. I will probably be posting some questions about that over the next couple of days.
Again thank you for the tip about debug. I know I will make use of that.
Another tip: do not try to write an entire program (or an entire fn ) all in one go.
Write the smallest (sane) amt of code (eg < 5 lines) and ensure it does exactly want you want.
Save a copy of that, then add a few more to the original
Rinse & repeat..
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.