Episode: 3551 Title: HPR3551: Bash snippet - some possibly helpful hints Source: https://hub.hackerpublicradio.org/ccdn.php?filename=/eps/hpr3551/hpr3551.mp3 Transcribed: 2025-10-25 01:18:53 --- This is Hacker Public Radio Episode 3551 for Monday the 14th of March 2022. Today's show is entitled, Bash snippet, some possibly helpful hint and is part of the series Bash scripting. It is hosted by Dave Morris and is about 25 minutes long and carries an explicit flag. The server is using the file, map file and then environment variables. Hello everybody, this is Dave Morris for Hacker Public Radio. I'm going to do a show today within the series Bash scripting. This is one I've called some possibly helpful hints, just a bunch of things that I've been doing in scripts lately and I thought I'd share just in case it reviews to anybody else. So I write a moderate number of Bash scripts these days. I know the Bash isn't a programming language but it's pretty powerful in what it can do all by itself actually and with other tools. It's like said an organ that type of thing, it's really, really capable. I've actually been writing the sorts of command script I suppose you'd call them for a long time since the 1970s on a whole variety of hardware and operating systems. Maybe we should talk about them someday. I remember them that is, Bash is my favourite because it's pretty flexible and also Linux itself, it's very flexible. Anyway, forget the history for now. I just want to talk about three things I tend to do in Bash scripts that assist some of the things I need to undertake some of the tasks I find I need to get a solution to. So the first one is to generate Bash variables from a text file. So you've got a text file which has got stuff like a keyword and a string or a number or something and you want to turn that into Bash variables. Second one is to fill Bash arrays with data from a file or a program or that type of thing. And the third one is to use environment variables or just general shell variables within the environment of the script to control the Bash script execution. So I'll expand on these. So first of all, generating a Bash variables. There's a Bash command, eval, eval, that can be used to evaluate the string as a command or series of commands if you want to put new lines or semicolon to between them. And the evaluation takes place in the current shell. So anything returned and in my particular example I'm using Bash variables is available to the current script. So this type of thing is available in a lot of programming languages, scripting languages where you might want to invoke a command within a script and the command is something you have generated in real time, I guess you'd say. If you were to set variables in a sub-shell which in fact is something like issuing some commands in parentheses or when you invoke a script or a function or something, then the variables are local to the sub-shell and they disappear when that particular process finishes. So the eval command, we haven't looked at it in detail but I've mentioned it in other contexts along this series. The eval command takes a list of arguments of any number I think which are just concatenated into a string and that string is taken to be the command to be evaluated. I should say that the eval command is seen as potentially dangerous then it will execute any command it's given. So if by some means rather you've ended up with a command string that says RM tilde slash star or something then it could go and delete all your files. How would that come about? Well, you might have made the mistake of allowing people to feed commands to the script that's doing it where that would be one of them. So you need to bear that in mind whenever you're doing this type of thing. Don't write a script that just executes whatever it's given to it. It needs to be vetted or you need to know exactly where that commands are come from before you invoke them. Now one of the particular cases where I use eval is for setting variables from a text file as I mentioned. I've got a file which is generated from the HPR show upload process and I want to grab the title of the show, the summary in relating to show and the host name of the person submitting. So I can generate an index file for any supplementary files which have come in with the show. I don't need to do this all the time but there are occasions when people send in example scripts or pictures and what that sort of thing. So I just wanted to be able to get these things and turn them into a bit of text in an HTML file. So in my script that does this, I won't go into details about it because it's quite complex but it uses eval with a, actually use a quoted string which in which is a command substitution which invokes said and said is looking for the keywords that the layer of this particular file, the keywords begin in column one and they are title or summary or host underscore name. So any line that matches one of those is picked up by said and is manipulated such that the end result is that keyword, which is all one word, an equal sign and then in single quotes, the string that follows it. So I show an example of how the said command would actually work all by itself and there's a reference to a very book called raw file here which is where I would have put the path to the file in the script. So just take that as a given and it's reporting back the host name, this is one of my shows is Dave Morris and blah, blah, blah, title and summary of them. So that's pretty basic said stuff and if you listen to my said series you should be able to decode that pretty easily and see what it's doing. So what Eval does is it runs the command substitution with the said command in it and the result of all that is a string which is actually separated by new lines but the way that command substitution works is that the new lines are turn to spaces. So these will be fed to Eval and Eval's quite happy to receive three variable definitions on the same line separated by a space, each one or space is. So what that does is to set a variable called host underscore name to one string, one called title to another string, one called summary to a third string and these are then available in the script that's called Eval. Now the way I've done this is not foolproof as I say in the notes because I'm wrapping the text in single quotes, if there was a single quote within one of these strings then it would break cause I haven't taken any particular action to avoid such a thing but it's working for now and I'm happy with that but I do need to work a little bit more on it to make it less fragile. Okay second one is filling bash array. So this is another thing I need to do in the context of writing scripts for HPR, janitorial things. I've got an index array and I want there to be sorted file names in that array and then I want to be able to process the contents of that array and I'm doing it because I've got a show that's come in which includes bunch of pictures so I want to be able to do some automation with the way I handle the pictures. Well how do I find the pictures? Well first of all there's a path which points to the directory in question which is called shoulder, all in capitals, SHOWWDIR. I use the find command against this path with a max depth option of one that means don't go down to lower directories and then it uses a regular expression thing. In find you have to say what type of regular expression you're using there's a hyphen reject type eGrep which I use so that causes the eGrep engine to be used in the regular expression. And the regular expression simply says dot asterisk backslash dot, yes so it's looking for any old text and including a backslash space, a backslash dot I should say, followed by either JPEG or PNG in upper or lower case. So that's how it finds pictures if you send in a picture that has some other form it won't work. Anyway it'll do that, does that quite well but that hasn't solved the problem yet but it's a component. So I've got an example here where you could define the array so I've got declare hyphen and a PIXPIX for pictures then I do PIX equals open parenthesis and then a command substitution with the find in it that I just mentioned it's all listed out in the notes here. The find is actually followed by a vertical bar to pipeline and it sends its output to sort. If you did that then the find and the thought will return a number of new lines separated lines containing filenames you know in alphabetical order but again as I said before the command substitution replaces new lines by spaces so what bash will see in this in the parenthesized list is a bunch of words or strings which are then fed into the array and that's great that works but it's relying on the fact that the file name delimitar is a space but it's permitted to have spaces and filenames it's not a good thing to do but it happens. So how would you make this better to avoid that one? I use the command map file I talked about map file in episode 2739 and you can also find information about it by typing help map file in a terminal so there's a little snippet here which is a declaration of the array again then we use map file then hyphen t which means remove the default delimitar the default delimitar is a new line then the name of the array picks then less than and I've split this into two lines with the backslash new line in it then we've got a process substitution which hopefully you'll remember from other shows in this series which is a less than sign immediately followed by an open parenthesis then you would put commands in there and close the parenthesis and the commands are defined as before exactly the same find and a sort in a pipeline you could have other delimitar here we'll talk about that in a second but the map file chops up what it sees on its standard input which is coming from this process substitution thing and it puts them one at a time into array elements if the array exists it will just overwrite it so that that's great you could change the other delimitar as I said and there are providing there are no files with new lines in them then you're good because a new line is valid in a file name it's a it's a thing I have never used not really encountered much but it's possible to do it I've done it by mistake I guess long ago in the next days well I didn't know what I was doing what I said here is that to be 100% safe and be protected from potential new lines in file name you can make find produces output using the hyphen print zero option which prints out every line or if you file in the case where it's reporting files with a null character at the end of it instead of a new line so map file can be told to use a null as the delimitar by simply giving it hyphen D and then a null string so open quote close quote so here's an example which shows the find with hyphen print zero the sort still works on that which is good I wasn't sure it would but it does and it sorts them correctly and you are then not prone to any any of the potential problems of funny characters and new lines and spaces or whatever I have to tell you coming to you that I discovered this information and messed around with it and tested it while preparing for this show so I'm going to go and update my script to use it once I've finished so the last hint or tip or snippet or whatever you want to call it is talking about turning debugging on in a script so I tend to use debugging statements in the script which get a little bit more complex than than others and I tend to write simple function which I've listed here which I call underscore debug in capitals for some reason I can't remember I did that the underscore just sort of makes it stand out a little bit perfectly valid character is part of a naming and can be the first character of the name so in there I test to see whether a global variable debug is zero and if it is then just return so effectively do nothing but if the debug is not zero then there's a loop which loops through the variable which is actually an array dollar at dollar at is a list of all the arguments to to a script or to a function so it's going to all the arguments that function and for each one it uses the print f command to print out its contents with a new line on the end and a d greater than space in front of it so when you look at it you can see well that's debug output the variable that I'm using to hold these these arguments is msg so I use that as the argument to print f it's very simple and that works pretty well it does pretty much what I want it to do so I what I just do I do is to plant a bunch of calls to this function throughout my script whenever I want to check that things I have read or calculated or whatever I want to check that they contain what I expect them to contain and you be surprised the number of times they don't and that's what debugging is all about but the thing is how do you turn debugging on and off you want something relatively simple but listed three possible ways you could do this the first one is is really clunky you could edit the script to set the debug variable to one when you want to turn debug on or zero when you don't but that means you got to keep editing the script which is the pain second one is you could set the debug level through an external variable which the script can see and the third one is to add option processing to the script so you recall the script with a minus with a hyphen capital D perhaps to mean turn on debugging and you would you would enable or disable it at that point I tend to use option three the option processing thing when I'm already scanning for and and dealing with options in my script but if I'm not doing that then I use choice two that is the external variable and that's I'm going to explain now so bit preambo I use vim as my editor and in vim I use a plugin called bash the port which I can set up boilerplate text within which is to be added to script or can be given as a default framework for a new script and I've got various definitions and declarations and comments and stuff that go in by default one of the lines that's particularly important is one which defines the variable script in capitals equals and then I've got dollar open curly brace zero hash hash asterisk slash close curly brace so that takes the default variable dollar zero which contains the name of the script as it was invoked so if you put the full path name and invoked the script from somewhere other than where the script lives then that will contain the entire path if you're in the directory where it lives and you put dot slash script name then it will just contain the dot slash and the script name whatever happens there that expression trims off stuff from the front of that string the dollar zero string and it specifies it's to keep doing that until it hits a slash and in other words it it will do this repeatedly until it takes out everything up to the last slash so just leave the name of the name of the script I did talk about this stuff way back in the early days of doing bash scripting now I've started adding two lines relating to debugging the first one is to define a variable called debug var or in capitals d-e-b-u-g-v-a-r set that to put this in in quotes dollar open curly bracket script close curly bracket underscore debug so that means debug var will contain the name of the script which had just chopped down to its last component well that's the base name isn't it yeah if you use the base name command instead followed by underscore debug in capitals then the next line is debug equals that's the variable that I want to use to control whether you see debug output or not then in double quotes dollar open curly bracket exclamation mark debug var colon hyphen zero close curly bracket close double quotes what that says is the variable debug var with an exclamation mark on the front of it it is to is an indirection to the variable whose name is in that variable so it's doing one level of indirection so it's using the contents and it's saying whatever that variable contains it if it if it exists it does contain something use it if it doesn't the colon hyphen business contain if you can't find it it doesn't exist then set debug to zero what that means it's a little involved that but it's um once as I say it's a bit of boiler plates I'm going to slap that in scripts by default and uh it's useful just to put it in without really thinking about it anymore but what it achieves is it it allows the script to be called with a variable definition before it on the same command line so if you had a script which is called test script and you'd call this variable test script underscore capital debug and I'm in this example I'm setting it to one then space dot slash test script folks test script and it will cause the internal debug variable to be set to one which will switch on all the debug stuff variables set on the command line are visible to scripts in fact variables set in the environment are visible to to a script whether they be exported ones which I talked about a few episodes back or just all new ones the one set on the command line only last while the script or indeed command is executing you could set an exported variable so one example here export space test script underscore debug equals one then on the next line dot slash test script but that variables can hang around after the script is run and you'd need to go and un-set it to make it go away so if you want to turn debugging off you would need to use the un-set command to delete that variable the thing that think about the putting it on the same line mean is that if you just run test script without that setting a variable preamble then it will run without debug so that's that's fine I definitely don't like to do the export business so when I give these more complex names to my debug variables that I've just been talking about test script underscore debug so there's less chance of them affecting other scripts than the one I'm trying just currently debugging if I just use the name debug then that might cause anything I run to go into debug mode that seems to be about ideas so I'm using sort of namespaces to keep things separate so in conclusion these are just the three things I found myself using in recent bash script which I hope might be useful to you if you have hints like this which you could share please make an HBR show about them we're always in need of shows I'm sure you know at the time of writing which is the 26th of February we are particularly in need and there's a lot of empty slots stretching out into the into the near future so from the near future forever okay then bye you've been listening to Hecker Public Radio at HeckerPublicRadio.org today's show was contributed by an HBR listener like yourself if you ever thought of recording a podcast then click on our contribute link to find out how easy it really is hosting for HBR is kindly provided by an honesthost.com the internet archive and our sync.net unless otherwise stated today's show is released under a creative commons, Attribution ShareLikeThoi.org license