Files
hpr-knowledge-base/hpr_transcripts/hpr2659.txt
Lee Hanken 7c8efd2228 Initial commit: HPR Knowledge Base MCP Server
- MCP server with stdio transport for local use
- Search episodes, transcripts, hosts, and series
- 4,511 episodes with metadata and transcripts
- Data loader with in-memory JSON storage

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-26 10:54:13 +00:00

274 lines
23 KiB
Plaintext

Episode: 2659
Title: HPR2659: Further ancillary Bash tips - 11
Source: https://hub.hackerpublicradio.org/ccdn.php?filename=/eps/hpr2659/hpr2659.mp3
Transcribed: 2025-10-19 07:09:04
---
This is HPR episode 2659 entitled Further Ancillary Mass Tips 11 and in part of the series
Bash Crypting.
It is hosted by Dave Morris and in about 28 minutes long and Karim and exquisite flag.
The summary is making decisions in Bash Part 3.
This episode of HPR is brought to you by archive.org.
Support universal access to all knowledge by heading over to archive.org forward slash
Donate.
Hello everybody.
This is Dave Morris.
Welcome to Hacker Public Radio.
So I'm doing another show in my Bash Tips sub-series because they're part of the Bash
scripting series.
This is the 11th episode on Bash Tips that I've done and this is the third of a
group of shows that I'm making about making decisions in Bash.
In the last two episodes we saw the types of tests that Bash provides and we look briefly
at some of the commands that use these tests.
Now we want to start examining the expressions that can be used in the tests and how to combine
them.
We'll also start looking at string comparisons in extended tests.
So let's look at Bash's conditional expressions.
So our examples of tests have contained these already but I haven't explained them and
I haven't listed them all.
What I've done here is to copy the contents of the appropriate section of the GNU Bash
Manual.
I've put a link in here as well and it's also in the Bash Man page.
I thought I would include this in the long notes because it's just useful to have a
reference point and finding these otherwise can be a little bit difficult.
Certainly reading the Bash Man page is quite a journey because it's huge.
So what I've done is I've taken that list, I've reproduced it into the notes but I've
added a few explanations where it seemed necessary to make it a bit more detail to explain
things a little bit better.
I'm not going to read them all out.
I'll just sort of whizz through them and refer to specific tests that I think you might
need to use in the simpler types of script.
So the conditional expressions are used by so-called extended test operators.
This is the double open and double close square brackets and also by the test command
and the single open and close square brackets which are built in commands and I talked about
these in the first part of this group of shows which I've referenced here, 2639.
The expressions can be unary or binary.
We operate as, take a single argument to the right, we'll see some of these in a minute.
Whereas the binary operators take two arguments, one to the left and one to the right.
Unary expressions are often used to examine the stages of a file, not all of them though.
There are string operators and numeric comparison operators as well.
When you are using the extended test operators, the less than sign and greater than sign operators,
then comparing two strings in that way, sort lexical graphically using the current locale.
So that means bash knows what locale you're using in your operating room with you using
the UK locale or you're in France or wherever and it will use the character sets which are
appropriate.
However, the test command and the single square bracket equivalent uses just plain ASCII ordering
when comparing things. Personally, I don't use string comparisons of that sort to determine
whether one string is greater than another. Can I guess be useful if you're doing some sort
of sorting type comparison, but it's a little bit prone to misunderstanding, I find anyway.
The other thing to say is that unless it's otherwise specified, the operators which operate on
files follow any symbolic links and operate on the target rather than on the link itself.
So if you've got a link to a file and you do some comparison with it, for example, to check
whether it exists, then it's not the link that you're, because the link can exist and the
file it points to can be can be vanished. So it's not the link exists that you're asking,
it's whether the file exists that it points to. Okay, it's getting a bit complex already. So I'm
just going to pop through these things relatively quickly as I say. I'm going to skip over a
thin number of them. The first one, the minus a followed by the name of a file, that's a check
to see if the file exists, but ideally you shouldn't use it because it's ambiguous, I think. I'll
come on to wine a minute, but I thought I just mentioned it. It's been deprecated, which I think
it's going to be removed at some stage. Minus lowercase d followed by a file name, if the file
exists and in is and is a directory, that will return true. And the minus lower case e file is
true if the file exists. We've seen that. I've used that in some examples already. There are quite
a lot of others relating to files, which I'm not going to go into. There is a minus h1 minus h file
is true if the file exists and is a symbolic link. So you can actually find out what things you
have in your directory, which are a symbolic link. If you need to, that'll be one that doesn't
follow through to the file end. So assuming that you could loop through files and determine which
ones were links and then check to see if the file they pointed to existed and on that basis
delete things which no longer pointed to a file. I haven't tested this, so it's not one of my
examples, but I guess you could do that. Here's one I didn't know before. There's a minus t followed
by a number of a file descriptor. I haven't talked about file descriptors, and I can't say I'm
more that up to speed with what, with how you work with file descriptors. Something I should maybe
do later on, but it can be used to check whether standard in, which is file descriptor 0 or
standard out, which is file descriptor 1 are terminals. So you can use minus t0 or minus t1 to
ask whether either of these are connected to a terminal. So you could have a job, a piece of
work script that was running detached from a terminal and could work out whether or not it was
connected through that means, but that's probably more advanced than I should talk about. I quite
like minus s followed by a file name, because it checks if a file exists, and whether it
has a size greater than 0. So you can do things like check the output file from something.
It might exist, but it might be empty, so it's useful to be able to say that looks like the
program didn't write anything, and that might be suspicious in a script. Here's one I had not
come across before and till I started preparing this list. It's minus v, in the case v, followed by
the name of a variable. If the shell variable referenced is set, that is, has been a assigned
a value, then it returns true. That might be useful just to find out things about variables.
Again, I've not created examples for any of these, and I've not really tested them. I'm just
prattling about them off the top of them. My head really. Minus z, followed by a string,
or a variable, is true if the length of the string or variable is 0. So I guess you'd put,
when it says string, it means a variable substitution in double quotes. So you, that way,
you could work out if, particular string that you'd captured from somewhere else,
had a length of 0. There's a corresponding minus lowercase n, followed by a string,
which is true if the string is non-zero length. So those are the bunch of unary operators.
There's a few binary ones. There's one where you can compare two strings. So you'd compare
string one, then two equal signs, and string two. You could also use a single equal sign.
That's true if the two strings are equal. When you use it with extended tests,
this can also perform pattern matching, which I'm going to go into detail about later.
The converse of the double equals is exclamation mark equals, that's not equals. Then we come to
string one less than string two. That's just about whether it's sorts before string one,
sorts before string two, and string one greater than string two, which is the opposite.
And the last set is where you have an expression that consists of an argument one,
an operator, and an argument two. The operators are things like minus EQ, minus NE. These are all
arithmetic binary operators, and they return true if the first argument is equal to, if you think
EQ or not equal to, if you use NE, not equal to argument two. So I've already done examples of
this in some of the earlier shows in this group. So I thoughtfully they're pretty obvious.
They listed that in the notes here, but I'm not going to go into tiny minute detail.
So if you want to do things like construct more complex expression where you can
catenate or combine the simpler expressions, then you can use an exclamation mark to reverse the
effect. So not, that's a not symbol, not operator, followed by the expression. So you could do not
minus E, and then some file name, which will check to see if it doesn't exist, return true if it
doesn't exist. The order in which these things are, the combined expressions are evaluated, can be
changed by putting parentheses around bits of the expression. So it changes the normal precedence
of operators. That's really to do with the ordering of not and or, which are sort of Boolean
operators. If you want to combine the results of two expressions using an AND operation, then
use minus lowercase A. That's where I said it. There's a potential ambiguity with the
unary minus A. There's also a minus O for OR, which is also a unary version. But these forms minus A
and minus O are only available in when used with test and with the single square brackets.
If you are combining expressions and wanting logical ANDs and ORs and you're using extended tests,
then you use the double ampersand and the double vertical bar, which I talked about in a slightly
different context in the last show. These ones short circuit, unlike the minus A and minus O.
So if I explain this in the context of command lists in the last show, so maybe I don't need to
go into detail, but the notes do attempt to explain this a little bit. Okay, so that's really
all there is to be said about in a formal way about this stuff. So conditional expression examples.
Example one, and there's a typical example of a not equals not minus E, I should say,
which checks to see if a file exists. So we've got if double open square brackets,
exclamation mark, space, minus E, space, then the name of a file in double quotes,
close square brackets, semicolon, then we echo, file, not found, and exit with the value of one,
and then finish the if, with the FI. So that's just, I'm not going to read out all these examples
because it doesn't seem necessary. But this is a typical example of the minus E operator,
and it's checking the existence of a file, and if it doesn't exist, it's going to abort the script
that it's in. So this is just a snippet. Exiting with one, I think I've said this several times already
in previous shows, means that the thing that's calling the script that's maybe calling the
script that you're writing can take error action on the basis of whether the called script
fails or not. As you will probably recall from the last show, this can also be written as a command
list, and I've shown an example of it. I won't read it out and explain any more because I think
it's pretty self-evident and there's plenty of information in these notes and the previous ones.
So example two is a complete script, though not very interesting one, which checks to see if a
particular directory exists, and if not creates it. So the directory that we're interested in
is stored in the variable, base, dirt, which is in capital. And then we check to see whether using
the minus D unary option operator, whether not in front of it, to see whether the directory exists.
If it doesn't exist, then we're going to create it. When you use mkdure, make dure to create that
directory. But as an extra twist, the make dure command is followed as part of a command list. So
it's followed by the two vertical bars, logical or, and in curly braces, an echo that says fail to
create it because the commands failed and exits with the value of one. Otherwise, it will echo
created, base, dirt, whatever the value. So I've included that one as a downloadable script
that you can grab and mess around with if you want to. Example three is looking at
checking the length of the string. The string might be the output from a command or input from
the script user, for example. So one way to check to see if the string is empty is using if,
and then use an extended test where you compare the parameter substitution expression,
dollar, open curly bracket, hash mark, reply, that's the name of the variable, close curly brace.
So if you remember from one of the earliest shows in this series, that's how you get a number
representing the length of the variable reply in this case. So we compare that with zero using a
minus EQ. And then if that is zero, then we echo, please provide a non-empty reply. That's certainly
one way to do it, it works, it's fine. Maybe a better way of doing it is to use the minus Z operator
against dollar reply and do it the same. So I wrote a little script just to demonstrate the two
things. It reads from the standard in to get a message which you can type and it then checks
to see if it's empty or not. And it does it using both methods. So I've run it with some test
data. In the worst case, please enter a string, it says and I typed okay and then it comes back
says you said okay. Then it does it again, please enter a string and I just pressed return,
it said please provide a non-empty reply. You can download this one to play with, it's called
bash 11 underscore EX2 dot SH. So there's tons more of these types of examples I could go into but
I think it's simple enough that you can experiment with these yourself if you're so minded.
What I want to talk about now is the bit where we were talking about a string comparison.
String comparisons are more powerful than some of the other expressions that we've looked at and they
one of the there's another operator that isn't in that list. Remember I copied that list so
it's not included there which seems a little odd actually but anyway there's another operator
which allows you to do string comparisons using regular expression. Now I'm not going to look at
that today and that's coming in in the next show, the next episode in this series because that's
one of the most powerful things but also pretty complex. But when we're doing string comparisons
in bash it can be a bit more than just simply comparing two strings. We can use pattern matching.
When we're comparing strings with test and single square brackets using equal equals or not equals
the exclamation mark equals the two strings being about treated as plain strings not surprisingly.
However when we use extended test operators that's the double square brackets it's possible to
compare the left hand argument with a pattern as the right hand argument. You can't swap them
right you can't have a pattern on the left and the string on the right so it's string on the left
pattern on the right and I've referenced the canoe bash manual about this with quite a lot of detail.
The pattern and pattern comparison stuff was all discussed back in 2007 8 and 2293
which are in this series of bash tips but it was talked about in the context of path name expansion.
You might want to go back and look at the the notes if you if you want to use this because this
is actually quite powerful. When doing string comparison in an expression like this then the pattern
is treated as if the x-t-glob E-x-t-glob option were enabled so you don't have to switch it on you
did have to do that with path name expansion if you wanted to get all the fancy stuff but it's here
without needing any further work inside extended tests. There's also another option called no case
match so you can actually make the pattern case in sensitive if you wish. So you can do some
quite sophisticated pattern matching but the pattern must not be quoted. If you do so then it's
treated as a simple string and all the pattern magic doesn't work. Now according to the documentation
it's possible to quote part of a pattern and that way you can treat pattern meta characters as
simple characters but I haven't managed to get that to work as I say in the footnote here. I don't
understand what they're getting at and I haven't found any comprehensive documentation that explains
this feature so I guess we'll leave that there for the moment. If I find out more I will pass the
message on. So here's some pattern matching examples then. So this is example 4 in this show
and what we're doing here is we're setting it as just a snippet of code. We're setting a variable
animal equal to the string grizzly bear. Then the test is if then double open square brackets
dollar animal equal equal star bear. Now there's no quote trying this. This is a pattern
asterisk bear and then close close the double square brackets semicolon then we echo first
is true we echo detected a type of bear colon then the the name of the animal the contents of
the variable. So this it tests for any string which ends with the letters B-E-A-R and that
includes a string that just contains the word bear so we'll be saying but that's actually quite
powerful. You can you can do in just sort of basic pattern matching that type of comparison can
be quite useful. So that's a that's just a simple glob type comparison. Example 5 uses an extended
glob in this case these we have a it's another snippet although this one exists as a complete
script that you can download and play with. So we've got a variable called STR which is set to
the title of this particular show and the comparison we make is between the the variable STR
equals equals but it's the pattern that's the that's the the important bit. So I'll concentrate
on that. Now this uses an extended pattern that you get with the xt glob usually which consists
of a plus sign followed by some stuff in parentheses. That format says one or more occurrences of
whatever the pattern is within those parentheses. Well the pattern in this case is a square bracketed
pattern. Remember that's the thing you can use for ranges of characters and so forth and inside
the square brackets we have a character class, POSIX character class which is
ALNUM alpha numeric but you have to write that as square brackets colon ALNUM colon closed square
bracket. So that's a character class which you can only use inside a character range expression.
That's then followed with a space and a hyphen. So we're saying that one or more of
alpha numeric characters spaces and hyphen we're matching with. So since the title is
further ancillary bash tips space hyphen space 11 you should match and if you run it you'll find
it does. Example 6 is another one of these extended patterns. This one uses an
at followed by a pattern list inside parentheses. This one if you do that matches one any one of a
list of patterns. The subsidiary patterns that the list of patterns is separated by vertical bar
characters. So in the actual script this is another standalone script that you can download
is simple though. There's a loop full loop which sets a variable called STR to
successively the strings dog pig rat and cat and also a blank string an empty string. The comparison
is being made between this STR variable and at open parentheses pig vertical bar dog vertical bar cat
closed parentheses. So what actually happens when you run it is you get back the indication that it
matched the dog it matched the pig but it didn't match rat because it's not one of those names in
that list. It matched cat but it didn't match the empty string. So it's pretty obscure if you've
not been brought up to this stuff if you've not learned this then it is quite obscure but I was quite
personally I was quite pleased to find that there was this facility in bash and do use it
and using it in this context is also extremely powerful I find. I don't have many scripts that do
it I have to say but after doing this show I will probably do probably be using it quite a lot.
So the last example and before we finish is example 7 and this is another one that you can
download bash 11 EX5 it is. This one is making a comparison of a pattern and a variable again and
but in this case the pattern is stored in a variable itself just to demonstrate that that's
possible. The pattern match is any word that ends with M-A-N and which is longer than three letters.
So the expression inside this that's being matched is a plus followed by a parenthesized list of
patterns and the patterns in this list was one. It's a square bracketed range expression and
inside it is a character class and it's the character class word so it's square brackets call
on word call on square bracket and that matches characters which are letters numbers and the
underscore. That's then followed is the pattern's not finished yet that's then followed with the
word man. So what it's saying is one or more word characters followed by M-A-N is a for loop
that goes through a list setting STR2 the values man, in the case woman, German, X-man,
romance and an empty string and it's the if checks each one of these dollar STR equals
equals dollar pattern. Pattern is what contains the pattern as you'll see if you look at the script
and if it matches it says matched and reports the string that matched otherwise it says didn't
match and reports that string and it starts off by reporting what the pattern is. So it didn't
it didn't match man because man doesn't have a preceding word character matched woman matched
German it matched X-man but it didn't match romance because the man didn't end it wasn't at the end
of the string and it also didn't match the empty string not too surprisingly. I pointed out
in the notes here that the expression that I use the if string that I use gets flagged as an
error by the spell check, not spell check, a shell check tool that I use inside VIM where I develop
these things and it complains that dollar pattern should be quoted to prevent glob matching.
So since that's what we're trying to do it's a little irritating that it does that but then you
can't expect it to know what I'm supposed to, it can't read my mind. It's possible with shell
check if you want to get into it at all to include a comment in front of the thing that causes a
problem that says ignore this effectively ignore error number SC2053 but I won't go into more detail
by the number. Okay so we now know that you can do some cool things with string matching using
patterns so I hope you find that useful and as I said already we're going to go on to look at
the other types of string matching which is using regular expressions which is even more powerful.
Okay that's it bye bye.
You've been listening to Hecropublic Radio at HecropublicRadio.org.
We are a community podcast network that releases shows every weekday, Monday through Friday.
Today's show, like all our shows, was contributed by an HBR listener like yourself.
If you ever thought of recording a podcast and click on our contributing to find out how easy it
really is. Hecropublic Radio was founded by the digital dog pound and the Infonomicon Computer Club
and is part of the binary revolution at binrev.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 status. Today's show is released on the creative comments,
attribution, share-like, free-to-life-sense.