LinuxQuestions.org
Visit Jeremy's Blog.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Software
User Name
Password
Linux - Software This 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


Reply
  Search this Thread
Old 12-12-2019, 12:17 PM   #1
taylorkh
Senior Member
 
Registered: Jul 2006
Location: North Carolina
Distribution: CentOS 6, CentOS 7 (with Mate), Ubuntu 16.04 Mate
Posts: 2,127

Rep: Reputation: 174Reputation: 174
Functions in a bash script question...


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?

TIA,

Ken
 
Old 12-12-2019, 12:34 PM   #2
michaelk
Moderator
 
Registered: Aug 2002
Posts: 25,702

Rep: Reputation: 5896Reputation: 5896Reputation: 5896Reputation: 5896Reputation: 5896Reputation: 5896Reputation: 5896Reputation: 5896Reputation: 5896Reputation: 5896Reputation: 5896
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...)
 
Old 12-12-2019, 01:23 PM   #3
taylorkh
Senior Member
 
Registered: Jul 2006
Location: North Carolina
Distribution: CentOS 6, CentOS 7 (with Mate), Ubuntu 16.04 Mate
Posts: 2,127

Original Poster
Rep: Reputation: 174Reputation: 174
Hello michaelk and thank you for the reply.

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

Ken
 
Old 12-12-2019, 11:00 PM   #4
chrism01
LQ Guru
 
Registered: Aug 2004
Location: Sydney
Distribution: Rocky 9.2
Posts: 18,359

Rep: Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751
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.

HTH
 
Old 12-13-2019, 06:19 AM   #5
taylorkh
Senior Member
 
Registered: Jul 2006
Location: North Carolina
Distribution: CentOS 6, CentOS 7 (with Mate), Ubuntu 16.04 Mate
Posts: 2,127

Original Poster
Rep: Reputation: 174Reputation: 174
Thanks chrism01,

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.

Thanks again,

Ken
 
Old 12-13-2019, 07:51 AM   #6
rtmistler
Moderator
 
Registered: Mar 2011
Location: USA
Distribution: MINT Debian, Angstrom, SUSE, Ubuntu, Debian
Posts: 9,882
Blog Entries: 13

Rep: Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930
Quote:
Originally Posted by taylorkh View Post
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!
 
Old 12-13-2019, 08:47 AM   #7
taylorkh
Senior Member
 
Registered: Jul 2006
Location: North Carolina
Distribution: CentOS 6, CentOS 7 (with Mate), Ubuntu 16.04 Mate
Posts: 2,127

Original Poster
Rep: Reputation: 174Reputation: 174
Thanks rtmistler,

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.

At this rate I may have to put this stuff in git

Ken
 
Old 12-13-2019, 11:36 AM   #8
taylorkh
Senior Member
 
Registered: Jul 2006
Location: North Carolina
Distribution: CentOS 6, CentOS 7 (with Mate), Ubuntu 16.04 Mate
Posts: 2,127

Original Poster
Rep: Reputation: 174Reputation: 174
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.

Ken
 
Old 12-13-2019, 12:39 PM   #9
rtmistler
Moderator
 
Registered: Mar 2011
Location: USA
Distribution: MINT Debian, Angstrom, SUSE, Ubuntu, Debian
Posts: 9,882
Blog Entries: 13

Rep: Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930
I think that's a true quirk where you need to diagnose it similar to what you've done thus far. I see no explanation for that behavior.
 
Old 12-13-2019, 05:35 PM   #10
taylorkh
Senior Member
 
Registered: Jul 2006
Location: North Carolina
Distribution: CentOS 6, CentOS 7 (with Mate), Ubuntu 16.04 Mate
Posts: 2,127

Original Poster
Rep: Reputation: 174Reputation: 174
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.

Ken
 
Old 12-13-2019, 07:29 PM   #11
Keith Hedger
Senior Member
 
Registered: Jun 2010
Location: Wiltshire, UK
Distribution: Void, Linux From Scratch, Slackware64
Posts: 3,150

Rep: Reputation: 856Reputation: 856Reputation: 856Reputation: 856Reputation: 856Reputation: 856Reputation: 856
In bash you cant have an empty if/fi construct if you need a place holder use ':' which evaluates as true ie
Code:
if [ -e /path/to/file ];then
 :
fi
It's also a good way to truncate a file, eg a log
Code:
:>/path/to/file
 
Old 12-13-2019, 08:06 PM   #12
taylorkh
Senior Member
 
Registered: Jul 2006
Location: North Carolina
Distribution: CentOS 6, CentOS 7 (with Mate), Ubuntu 16.04 Mate
Posts: 2,127

Original Poster
Rep: Reputation: 174Reputation: 174
Thanks Keith Hedger,

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

Ken
 
Old 12-17-2019, 08:18 PM   #13
chrism01
LQ Guru
 
Registered: Aug 2004
Location: Sydney
Distribution: Rocky 9.2
Posts: 18,359

Rep: Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751
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.
 
1 members found this post helpful.
Old 12-17-2019, 08:39 PM   #14
taylorkh
Senior Member
 
Registered: Jul 2006
Location: North Carolina
Distribution: CentOS 6, CentOS 7 (with Mate), Ubuntu 16.04 Mate
Posts: 2,127

Original Poster
Rep: Reputation: 174Reputation: 174
Thanks chrism01,

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.

Ken
 
Old 12-18-2019, 09:43 PM   #15
chrism01
LQ Guru
 
Registered: Aug 2004
Location: Sydney
Distribution: Rocky 9.2
Posts: 18,359

Rep: Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751
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..
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
OSE system call functions to Linux Sytem Call functions required roshantraj30 Linux - General 0 06-08-2009 02:06 AM
LXer: OpenOffice.org Calc functions, part 1: Understanding functions LXer Syndicated Linux News 0 03-31-2007 12:01 PM
Slackpkg: missing something in /usr/libexec/slackpkg/functions.d/dialog-functions.sh michelino Slackware 4 03-20-2007 12:22 PM
Converting php5 socket functions to php3 socket functions mrobertson Programming 0 06-23-2005 09:11 AM
pointers to functions/member functions champ Programming 2 03-28-2003 06:22 PM

LinuxQuestions.org > Forums > Linux Forums > Linux - Software

All times are GMT -5. The time now is 09:45 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration