Files

259 lines
24 KiB
Plaintext
Raw Permalink Normal View History

Episode: 2689
Title: HPR2689: Bash Tips - 14
Source: https://hub.hackerpublicradio.org/ccdn.php?filename=/eps/hpr2689/hpr2689.mp3
Transcribed: 2025-10-19 07:35:33
---
This is HPR Episode 2689 entitled Bash Tips 14 and is part of the series Bash Cripting.
It is hosted by Dave Morris and is about 28 minutes long and carries an explicit flag.
The summary is more about loops for loop, break and continue.
This episode of HPR is brought to you by archive.org.
University Access to All Knowledge by heading over to archive.org forward slash donate.
Hello everybody. Welcome to Hacker Public Radio. This is Dave Morris. I'm doing a show
in my Bash Tips series today and I've recently done a bunch of shows entitled Making
Decisions in Bash and looked at loops there. I looked at while and until loops but I
mentioned that there's another loop construct which uses a four verb, four loops and I've
not really covered that. I've used them in many shows. That really fully explaining them
and I thought this was the time to make good that deficiency. While I'm at it I'm also
going to look at the command break and continue which are used for when using loops.
So in Bash there are two formats of the four command. The first one I'm actually using
the syntax that's used in the GNU Bash Manual which is less pretty but is probably more
correct than sort of thing I've been using in previous shows. So the actual command consists
of the word four FOR, then a space and then the name of a variable. Then that can be followed
by optionally the word in and then the list or words. If you are doing this, if you have
these then there's a semicolon that follows that or indeed a new line. Whenever there's
a semicolon in this syntax you can also be replaced by a new line so you can spread out
your command over multiple lines. Then the word do and then a list of commands of any
anything similar to the other loops who've looked at another semicolon or new line and
the final word is done. So that's the whole structure. The thing that's the in words part
refers to is either a literal list which I'll do an example of in a moment or something
which will expand to provide a list or whatever sort of expansion is relevant. What the loop
does is it cycles for each member of the list setting the variable whatever you called it
to each successive member and executing the commands at each iteration. So my example is
four color in red, green, blue. So color is the name of the variable and the list is red, green,
blue. They're just words unquoted. If the words needed had spaces in them, we wanted to have bright
red with a space in between. You'd have to quote them to make it just the one word. Similar sort of
issues pertain he has. You would find all over bash when you're using arguments to programs
or scripts or whatever. Then after that list is a semicolon and do. I like to put the two things
on the same line. You don't have to. Then the next line is echo and in double quotes dollar color
and then the last line is done. Then I like to indent the commands that are inside the loop just
to make them clearer. And in fact if I use the Vim Editor with bash or SH as its syntax file then
we'll do that automatically for me. So just like the look of it it's easy to read. So running that
will output three color names one per line. I'm bothered to run that one because it's so simple.
Another example might be four space file or files the variable space in. Then the list is not
actually a list but it's an expansion expression. So asterisk.mp3 semicolon space do. Now we'll in the
the current directory that you are running this. It will look for any files which end with
dot mp3. And one pitfall that I haven't gone into in the notes here but I mentioned in earlier
earlier shows in this group is that if there are no mp3 files in that directory you will get back
the string asterisk dot mp3 and you can control whether you get that or not with some options which
I went into in quite a lot of detail. So be aware of that as I was typing this I'd forgotten to be
perfectly honest. So I'm mentioning it now because it's a good chance you you might have a memory
like mine you've gotten to. Anyway the command in this loop is echo dollar file in quotes. So we'll
just print out the name of the file. So it's just a way of doing the equivalent of ls asterisk.mp3
except it's a bit cleaner you don't get all the other garbage you get with ls. So a list like that
might be empty though not in the case of sts.mp3 and as you've enabled the null glob option but it
might expand to nothing might be empty. So it's perfectly legal to have a format which consists of
for name whatever the name of the variable is in and then nothing then a semicolon. So that's
okay nothing will happen. It won't run at all because there's nothing to do. Now there's a special
form of the this format of the loop where you can write it without the in words part which case
you don't actually need to put a semicolon before the do. What this form does is it cycles through all
the positional parameters. So when you start your bash shell up you usually don't have positional
parameters attached to you but if you create a script and run that then you can as you know hand
it some variables strings or numbers or whatever and those are the arguments and they're called
dollar one dollar two dollar three etc. So running it this way is the equivalent to writing
four space names base in and then in double quotes dollar at sign. Dollar at sign is one of the
special variables within bash which refers to the entire list of arguments that you have in a
script or a function. So I've written a pretty straightforward example which is called bash 14
EX1 and you can download it if you want to but it's also here to be looked at and it simply consists
of for loop for arg space do called a variable arg because it's an argument echo in double quotes
dollar arg done. So if you run that and give it the four words let joy be unconfined as you would
do because then you get back one per line let joy be unconfined. The return states of four command
is the exit status of the last command that executes within it so that list of commands the last one
whatever it returns to a fourth will or indeed something which is not zero or one will be what the
for loop returns. I personally never found that would be particularly useful but you might want to
test that sort of thing I'm not sure. If there are no items when the list word becomes to be expanded
no commands are executed and the return status of the whole shebang is zero she's pretty long. So
that's the first format you've seen me using it in various examples and so on. There'll be other
cases in this this collection of scripts where I use variants of it. So the second format is a bit
more complicated it consists of the word four then a space then three expressions enclosed in double
parentheses then the semicolon do the list of command semicolon done. So I've used the the usual
syntax here and the expressions within the double parentheses I'm referring to as expression one
expression two expression three separated by semicolon so you have to use this this particular
format. So these are arithmetic expressions as I think I just said and it uses these the loop
uses these to determine how many times to to iterate. So expression one is an arithmetic expression
which is evaluated at the start and it usually consists of a variable being set to some value
where that value can be an expression or whatever. There needs to be a variable because the loop
is tracking the iterations by using the variable that's not strictly true but if you can if you
will come on to why I hesitated there slightly in a moment essentially it's usual to to set a
variable to a value. There'll be examples shortly. Expression two is also an arithmetic expression
which is evaluated at each iteration of the loop. When each time it evaluates to a non-zero value
the commands in the loop are executed. Expression three is another arithmetic expression which is
evaluated each time expression two evaluates to a non-zero value so traditionally that's used to
increment or decrement your variable. So here's an example. So we've got four space two open
parentheses i equals one so the variable i is being set to one. Remember the double parentheses
means it's an arithmetic expression. We'll list up in this case and the all the rules about
spaces and stuff have gone out the window you can use them or not use them as you wish. So after
i equals one semicolon then the second expression is i less than 10 so that the comparison is
going to be run every time the loop iterates to see if the variable i is less than 10 and the
third expression after semicolon is i plus plus so that's one of those arithmetic increment
that's actually a posting increment so it will return i with one added to it and then after
the closed double parentheses we've got semicolon space to do and then in the body of the loop
that one command we have is echo dollar i. So that will just output the numbers one to nine one
per line. Now as I alluded to this quite a lot of flexibility allowed in the expressions you can
use in this format and the rules of shell arithmetic apply and I've put a reference to shell
arithmetic but we've talked about this in recent shows in fact so it's all very flexible about
spaces you don't need them after the open parentheses and nor before the closed parentheses could be
nice to add them I personally don't but I've definitely put them between the expressions and
that I also put them either sides of an equal sign when setting up the variable which you can't
normally do in bash. The paths I want won't deal with that which I've always felt was the same.
When you're referring to variables you don't need the leading dollar in fact if you put it in
it does have some side effect I haven't gone into what they are here I'm not sure I need to
particularly but I'm going to do a show after this one about potential traps that you might fall
into when working with loops so if I come across any any particular problems in that area I might
go into a bit of detail there but for the moment I don't think it's a big deal you should try not
to use the dollar sign in front of variables in this case you don't need them and of course within
these expressions any of the shell arithmetic arithmetic operators can be used so and there's a lot
of them as we saw I think one of the the recent shows there's a huge big list and I've referred to
the page I got that list from so you can go and look at that so my next example I'm setting i2
and then an expression of 78 plus 20 over 2 minus 4 times 12 which surprise surprise the answer
to that is 1 but it's just me being silly and giving you a more complex expression and then instead
of i being less than 10 I've put i not equal to 10 we should achieve the same thing
so that will just do exactly the same things the previous simpler looking like but it just shows
how much flexibility there is I thought I'd do a more complex example of what you can do in one
of these these types of for loops one of the arithmetic operators that you could use if you
wished is the comma operator and there's not a lot of information about it if you look in the
GNU bash manual at the point I've I've referred to the one in the list there's simply a thing that
says expression 1 comma expression 2 and the notation to it says comma which is yeah there's
there's very very little documentation about it I think possibly because when they added this to
bash it was added possibly at the request of c programmers because it's a funk it's a it's a
facility that's available in c basically it's a list of expressions that get executed and the
result of the whole list is the result the last expression so preamble to what I'm actually doing
here my for loop consists of four space open double parentheses i equals 1 right big deal r but then
there's a comma and then I've got j equals 100 semicolon so in that first expression there are
there's a comma comma list the list can actually be multiple but I've just made two entries here
you can have as many as you want to think I'm not sure there's a limit I haven't
experimented with that the expression to the test bit is checking to see whether i is less than
or equal to 10 and then the third expression increments i by 1 so it's i plus plus but there's
another comma and we've got j plus equals 10 so the variable j is being incremented at each time
around the loop by 10 so the body of the loop consists of an echo where we're going dollar i and
dollar j and there's done I've written this out as if it was being typed on the command line in fact
it was just to so I could catch it and put it in the notes and when it runs you get the values
1 to 10 for i and you get 100 incrementing in steps of 10 out to 194 j so you can see that would
that that could be really quite powerful you could do some clever things with that so there's a
little bit of stuff in the notes but experience a bit more than i've done there this one's got a
downloadable copy which is bash14ex2.sh you can grab and play with if you find it interesting or
want to experiment to see what else you can do with it so the final point about this this format
the full loop is that if any of the expression 1 2 and 3 is missing then it's taken by the
loop to be 1 so if you wrote 4 open double parenthesis i put spaces here just to make it clear
a space semicolon space semicolon space but you could just type two semicolons one after the other
in other words the the three expressions are missing completely and the closed double parenthesis
comma do and then the commands semicolon done however else you prefer to write it out
and this is an infinite loop because everything returns 1 so it'll always have a non-zero value
in the test so we'll just keep running forever not incrementing anything or doing anything
there's no variable to be incremented there's nothing no variable it could be used in the
body of the full loop it will just run forever so the return value of this type of four command
with the arithmetic expressions is not surprisingly the exit stages of the last command in the
command list but it can also return the value false if any of the expressions is invalid so if
you somehow manage to divide by zero or something like that it will return false value and stop
didn't actually test that i should maybe have done i'll leave that for you to look at so the other
topic i wanted to cover i mentioned is the break and continue command and we've we've seen these
i think in various contexts through the the other shows under the bash tips heading um
definitely use continue in the recent past didn't explain it all in all that much detail
and to try and explain it a little bit more this time both of these commands are built in one so
they're not exterior programs anything they're part of bash they're in fact inherited from
bash's predecessor the born shell and i've given the link to to them in the canoe bash manual
they're both used for changing the sequence of execution of a loop that's a full loop a while loop
and tin or an until loop when you to select loop which is effectively a loop yeah we haven't looked
at that we need to do so and i haven't got it scheduled up we will look at it at some point
because it's actually quite useful and we need to see how it can be used so let's look at the break
command the break command is the word break followed optionally by an integer which is great
than or equal to if you emit this integer then it's taken to be it specifies that the
nth enclosing loop is to be exited so my example is fairly simple it's a full loop using the
format with a list of words for i in and then i've used a double brace expansion the first brace
expansion is open curly bracket a dot dot c close curly bracket then another curly bracket
opening one dot dot three close curly brackets semicolon space do you'll remember and i've
referenced back to the show where i talked about this quite a lot of detail actually i did it
it's very cool i think it's a fun fun feature 1884 i talked about it and i've also referenced the
canoe bash manual chapter on brace expansion so that loop we haven't finished talking about what's
in it yet but the loop will generate the values a one a two a three b one b two b three etc
and it'll it'll do do that until it's used them all up so inside the loop we echo that that
variable i and but we've added another thing here which is a test so in the single square brackets
we put in quotes dollar i equals equals quotes b two close quotes close square brackets so we're
testing here to see if the the variable i contains the string b two this is a command list so it's
followed by double ampers and and then the word break so if we if we find get back a value of b two
then the loop just stops it exits when you see it running and i've run it and captured the output
you get a one a two a three b one b two and then it stopped so here's a more complex example
this one contains a loop within a loop the inner loop simply repeats the current value of the
variable i three times and it uses echo space minus n to suppress the new line so you just get
them on the same line this case we want to exit both loops whenever i get to b two i want to stop
both loops right the first four is the same as the one we saw in the previous example then there's
one inside it four j in then in braces one dot dot three and then we echo minus n in quotes dollar
i then the test inside this inner loop is dollar i equals equals b two that these are quoted variable
and string and ampersand ampersand this time I've got a brace around two two commands one is echo
just because after the last thing it was printed no new line was was output so we want to
output a new line this time we're using break space two and there's semicolons between these we
talked about this stuff in an earlier show how the the curly brackets are actually effectively
commands they have to be separated out and the things within them have to be separated out by new
lines or semicolons so that next is the done which closes the j loop then we have an echo
so that every when the thing is running before it's killed by the break then we output a new line
after the three repeats of the value of i hopefully that makes sense and that's an example what it
look like a one a one a one a two a two a two etc when you get to b two just get the one and then the
the test detects that it is the required value and it breaks both loops it kills the inner loop
and the outer loop the whole shebang stops i put these loops that i've just been using as examples
into a file that you can download if you want to to experiment with them and it's called bash 14
e x three dot s eight so that's what break does it exits loops and there's the continue command
and continue is that the word continue followed by a space and an optional number and it's
take it be one if it's missing and it's it's got to be one or greater the command's effect is it is
that the end enclosing loop must be resumed which is amusingly the bash manual terminology here
when it says be resumed what it actually means is wherever the continuous is invoked the rest of
that loop is skipped and then the loop continues with the next iteration that it would normally have
done so i've got an example here because this is getting a little more complicated not much
but just a little bit bash 14 e x four dot s h here we have pretty much the same examples we saw
before with the loop within a loop where a is being set to the values a one a two a three etc
the variable i is being set to these i should say then j within it is being set to values one two
three is and so on and we're outputting the value of i with a echo hyphen n but the test is
different this time using the extended test format with the double open and clothes brackets
square brackets and we're comparing dollar i with a glob style string match which is simplicance
is a b question mark so if the contents of a variable i begins with the b and contains another
letter another character then the match will trigger and we are doing similar things we did with the
with the break example issuing an echo command which just generates the new line that would be
missed otherwise and this time we're using continue we're using continue with the number two so
that will resume two loops probably makes more sense when you look at what it does it causes the
outer loop to continue with the next letter number combination but it would be using to set
the variable i to if you run it you get similar stuff to the previous example a one a one a one
etc and then when we get to the b's we only get b one once b two once b three once because each of
these matches the test so the continue command simply jumps past everything else within the nested
loops and goes on to the next value it's not spectacularly useful example but i'm sure that hopefully
explains that all of the stuff that's going on and will give you some thoughts about how you
would use it yourself whenever more specific requirement so i'm going to finish off with an example
this one's bash 14 EX5 it's not hugely complex but it's showing that the list when you're dealing with
the four loop in the first format with it using four variable in and list of words that list
can be anything so this time i've gone to my favorite user share dict words that file of huge numbers
of words i'm using the shuff command which is going to grab 10 random words from it but i've
used grab in this case to filter out all the words that end with apostrophe s because so many of
these seem to be arbitrary and ridiculous as i said in the notes at one point i got back the
word logger head apostrophe s well i can't imagine when you would use that usually use the logger
heads as at logger heads meaning in an aggressive confrontation so when would you ever
talk about the possessiveness of such a thing and if you're talking about logger head turtles you'd
put the possessive part on the turtle surely anyway i mean you could it's not that it's not
English but it just seems stupid so this one is just a very simple loop except that the source
of the words is a command substitution so we've got four w in then dollar open parenthesis we've
got the grep grep space hyphen capital E that invokes the er form of regular expressions
then space hyphen v which says give me all of the lines which don't match the regular expression
and the regular expression consists of in double quotes apostrophe s dollar so anything that ends
with apostrophe s the end of the line we don't want then the file we're dealing with the
is user shared dict words we pipe that into the shuff command with hyphen n space 10 so we get back
10 of the words that grep returns and then semicolon closed parenthesis semicolon do and we
simply echo the word dollar double and that's the end of the loop and it's done that ends it
and um i gave an example of running this and they're nice they're random you could do something
useful with them i've just listed them so please enjoy so that's the end that's what i'm going to
talk about you've been listening to hecka public radio at hecka public radio dot org we are a
community podcast network that release the shows every weekday Monday through Friday today show
like all our shows was contributed by an hbr listener like yourself if you ever thought of
recording a podcast then click on our contributing to find out how easy it really is hecka public
radio was founded by the digital dog pound and the infonomicon computer club and it's part of
the binary revolution at binwreff.com if you have comments on today's show please email the host
directly leave a comment on the website or record a follow-up episode yourself unless otherwise
stated today's show is released on the creative comments attribution share a light 3.0 license