Video summary
The video introduces the concept of shell scripts as automated routines designed to simplify repetitive tasks within a compute environment, particularly in bioinformatics where reproducibility is crucial. The instructor demonstrates basic file management commands, such as removing unnecessary files and creating empty ones using `touch`, before focusing on analyzing genomic data stored in `.gbff` files. A primary example involves counting the number of unique gene locus tags within these files; initially, a simple pipeline using `grep` to find tags and `wc -l` to count lines yields an inaccurate result due to duplicate entries caused by the file format. To resolve this, the script is enhanced with `sort` and `uniq` commands to eliminate duplicates before counting, ensuring accurate data analysis.
To increase the script's efficiency and versatility, the lesson progresses to implementing loops using Bash syntax. The instructor explains how to use `for` loops to iterate through multiple files, initially hardcoding specific filenames like "Atlanta" and "London." This evolves into utilizing variables and special Bash parameters like `$@` to allow the script to accept any number of arguments or process all matching files in a directory automatically using wildcards. The tutorial also covers best practices for writing readable code, such as adding comments with the `#` symbol to explain sections without executing them, and correcting a common mistake regarding the `echo` command's default behavior of appending newlines.
Finally, the video addresses how to make scripts standalone and executable by modifying file permissions with `chmod +x`. The instructor highlights the importance of the "shebang" line (e.g., `#!/bin/bash`) at the top of a script, which informs the operating system which interpreter to use when running the file directly. Without this line or explicit invocation of the shell, the system treats the file as plain text rather than executable code. The session concludes by demonstrating how these elements combine to create robust scripts that can process multiple genomic files efficiently, handle varying input counts, and maintain clarity through proper commenting and structure.
Read the full video transcript
Okay. Um so for this example we are
going to be creating a script. Uh a
script is uh essentially a routine that
you can tell uh that you can tell the uh
compute environment uh to run and it can
make uh repetitive tasks easier. Uh it
can it uh it's also helpful for these
repetitive tasks because uh you're less
likely to make typos uh just based on uh
pure chance and uh you will be able to
reproduce your results which is becoming
increasingly uh important in
bioinformatics if you can demonstrate uh
how your results were obtained. So
to do this script uh I've navigated back
to my home directory but where we're
going where we are going is the
data directory and inside the data
directory we're going into the genomes
directory.
Okay.
Um so inside of genomes uh we would have
seen this a little earlier uh if we list
here we have uh several GBF files and uh
some of the files that uh we created
earlier. Uh just because we don't just
because I know we're not going to need
them anymore. I'm going to make a point
of actually removing um removing uh bad
file and lengths.txt.
So I can do this by RM bad file. I just
typed bad and tab to complete it. And
similarly I will do rm
len tab to complete. And if I hit or if
I use ls again we can see that we only
have the gbff files now which is
perfect.
Could you do both in one line? The
reason I did it in two lines is because
I forget. We can try it together and see
what happens.
Uh let's make a couple test files. Uh a
command you can do to make an empty
file. I don't know how often you'll use
this, but you can use touch uh the arrow
uh test one. T
Whoops.
Uh the mistake I made there is I was
trying to use touch like I would use cat
when the reality is that uh instead
touch doesn't need one of those uh arrow
uh operators. I can just hit touch test
one.txt.
Uh I'm going to touch another file.
And so if I list the directory now I
have test one and test two. So the way
the easiest
perhaps the most efficient the fewest
keystrokes would be rm
star.txt because uh our other files are
gbff at the end and the ones we want to
remove are txt. Um but for the sake of
demonstration we can rm test one.txt.
I'll add a space test 2.txt txt and hit
enter to see what happens.
The shell appears to be happy. We can
hit list
and our GBF files are still there and
our txt files are gone. So, great
question, Katherine. I learned some I
learned something else today.
Okay.
Now looking at our uh GBA FFF files uh
if we want to know what's in them recall
that we can use uh the less program uh I
will just look at the first one which is
Atlanta. So I'll type ATL tab and enter.
And so I myself don't work with uh these
types of files. So um
we can see now visually that there uh
appear to be uh two columns. Uh one
column appears to have some labels. So
I'm seeing locus definition accession on
the left side and then uh uh uh next to
these uh there are some text fields. So
under locus I'm seeing this um some
version title
etc. And as we scroll through here
we can see that there are some uh some
aspects of this file that repeat. uh
specifically um when we're looking
underneath the features and the
location/qualifiers portion of this
file,
we can see that uh there are locus tags
for uh genes that are contained within
this GBF. So this gene for instance has
this locus tag. If we look a little
further uh down the file um there is
another locus tag.
Ah yes we are in Atlanta.gdff.
And so I can see that there are some
repeating patterns in uh in this file.
And so we can start to ask questions
about what's contained within. If I were
to use something like WC to count all of
the lines in the file, uh that might
give me something I want to know. But if
I wanted to know for instance how many
of these uh locust tags uh and by proxy
how many genes are contained within the
file uh WC would give me a a very large
overestimate on its own because it's
counting the number of lines when the
reality is a lot of the lines of this
file are things that we're just not
interested in.
So, this is where we can uh use some of
our pipes. And we can do this inside of
a script. So, I'm going to hit Q to get
out of less.
I'm going to use nano to create our
script. Uh just because uh since we're
already in the shell environment, it'll
be easy to do so. So, nano. And then I'm
going to call I'm going to call this
script count
tags.sh.
So two things to note about this name.
The first is uh when I first
demonstrated nano I did not give it a
name and you don't have to but uh it is
helpful uh to name your file from the
beginning. And the second is the
extension. Now again uh I mentioned that
uh the shell is generally agnostic to
file extensions. Um but it it helps us
as humans differentiate what we're
looking at. And so what we're creating
here is a shell script. And so
should indicate to us the humans that um
the file count tags is a shell script
similar to how a txt extension would
indicate to us that it would be a text
file. So I'll hit enter. We can see uh
we're in GNU Nano7.2 and our working
file is count tags.sh sh and there's
nothing in it because we just created
it.
So, I'm going to
work through a script that first is
going to uh look at that atlant.gbff
file and try to find out how many tag
how many locust tags are inside it.
So,
we can start by uh using the echo
command I showed you earlier,
which just outputs uh some text to the
standard out.
I'm going to use a uh special option
with echo called uh dash n. Uh, this
tells Echo that I want uh after I give
it some text, I want it to put a uh a
new line character in. This is
equivalent to pressing enter on a
keyboard. Uh, but by default, Echo
doesn't do this. It'll just string
everything together on one line. So, I'm
trying to create a second one.
Uh, to tell Echo uh what to write inside
these quotations, uh, I'm going to
write,
how do you spell Atlanta? Atlant
GB FFF
colon and
close the quotes. I'm going to press
enter and go to a new line. And this is
where I'm going to show you a new
command called GP. Uh, Grep is a program
that can look through uh, look through
text. Uh, whether that text is in the
standard out and you are piping it from
another command or it that text is
inside of an existing file. Uh, GP will
look for uh, something called a regular
expression or you can think of it as
just looking for a match uh, to some
text that you give it.
So, uh, I will use the GP command.
I'm going to tell Grep that I want to
find all of the parts of the text that
start with locus tag
because you'll recall this is uh
this is one of the repeating portions of
our file.
GP also needs to know what file to look
in. So I will tell it we want to read
Atlanta.gvfff
and uh because this is uh going to
because I know this is going to output a
lot of uh individual lines as a result
of this GP command uh I'm instead going
to catch the results uh with the WC
command and transform it into something
a little more informative. So using the
pipe I just I demonstrated earlier, I'm
going to take all of the matches that GP
produces, I'm going to feed these into
the WC command to count uh what to count
the number of lines that are coming out
of the output. And in order to get only
the lines uh I will use the -L flag.
Now to save in nano
you can the best practice is to hit
control O where it'll give you the
option to file name to write uh we're
writing to count tags.sh
uh if you were for instance to uh hit
controll x without saving it is still
going to give you the option to save a
modified buffer.
Okay.
So now we have this count tags.sh file.
If we want to see what's inside, we can
use cat and this will show us
this will show us the contents of the
file, but it won't actually run it. We
can see that our echol line is there and
that our grap line is there. If we
actually want to run this script, we
have to
we have to tell the shell that uh we
want it to interpret the contents of
this file in bash. The way that we do
that is by first typing bash. And then
uh we could say we want to run our count
tags.sh. I hit count underscore and tab
complete. And now when I hit enter,
you can see that uh the output uh of our
script is written to our shell here. Uh
the text.gbf
is there and we can see this number
12,237.
So, um
the
to demonstrate
um that the script is working properly,
I want to show you just the GP portion
of it. And so,
uh instead of running the script again,
I'm going to type the GP command. So
rep, we're doing uh slashlocus
tag equals
that
Atlanta. Uh locus tag is the string
we're trying to match. The file we're
looking in is Atlanta.gbff.
And if uh I feed this to the WC command
with the L option, it also spits out
12,237.
Uh for the sake of demonstration, I'm
going to pull the previous command back
up. I'm going to backspace the WC part
and the pipe part because I think it's
interesting to show you uh what is
happening under the hood. Um, this is
about to output 12,000 results. So,
sorry if this lags,
but we can see that um, Grep is spitting
out all of these uh, locus tags to our
standard out.
Now this is well and good but um if we
are relying on the count that we were
given by the script we just made uh we
may notice a problem which is that um
there are duplicates in these locust
tags and this is a consequence of the of
the format of the original file. But um
we can see that the one ending in 435
happens twice. The one h ending in 545
occurs twice. And this happens in a lot
of cases. Presumably not all of the
cases because we got an odd number from
our original script. But uh enough that
it's a problem.
So there is something we can do to fix
this which is to try and find only the
unique um try to find only the unique
results uh of the GP command. So to do
this I'm going to clear my screen. I'm
going to go back into our script by
typing nano
count tags.sh and hit enter. And we're
back in our script.
Now,
uh oh, quick trick. Uh if you want to
get to the end of a line, you can use
the end button on your keyboard. So, uh
I'm at the end of the first line here.
If I hit down, it puts me in the middle
of Atlanta because uh Nano treats each
of these uh each of these characters as
an individual column in the file. So,
technically that's right below the end
of the first line. If I want to go to
the end of the second line, I can hit
the end button on my keyboard and go to
the end of WC-L.
So
what I want to do is find only the
unique tags that are
uh being found by the GP command or
rather I want to filter the results of
the GP command so that only the unique
tags are remaining. So to do this, I'm
going to add another pipe to uh Whoa,
that wouldn't work.
That wouldn't work because WC just
outputs a number. Instead, I want to go
back here to after the GP command. What
I want to do first is sort the results.
And any sorting here works. We're we're
dealing with text. So the default
lexographic sorting is just fine for us.
We don't need any extra parameters. Um
and this sort part is important because
the next thing we're going to do is use
the unique program which is just
shortened to uniq.
What unique is going to do is look at uh
the adjacent lines in a file to see if
there are any duplicates. So
if
if there were two duplicates in a file
and they were uh separated by a few
lines, unique wouldn't remove them
because it's only looking at the
neighbors of that line. But because
we're sorting the file first, all all of
the all of the things that are
duplicates are going to be right next to
each other because they've been sorted.
So unique is going to be able to look at
all the neighbors, remove the duplicates
and then to finish up uh I want to count
the number of lines that come out of
this pipe. So first GP which for which
the results are sorted for which the uh
the unique uh tags are found and I want
to count all of these with WC-L.
So I will follow best practice here and
then hit control O to save. I will hit
enter and then Ctrl X to exit.
So now when we run our script with bash,
I'll do count
tab tags.sh.
If I hit enter now, we see that the
number has changed. And this is because
we were able to use sort and unique to
uh to remove those duplicates.
Okay. Do we have any questions thus far
about the script or any of the pipes,
any of the programs?
Sorry, can I see your uh
your accounts uh tagsh to see if I wrote
correctly?
>> I'm sorry. My uh speaker was muted for
the first half of your comment there.
>> Can I see your shell script? Just one
sec to see if I wrote it correctly.
>> Yep.
>> Thank you.
>> I can do that. I will go back into nano.
I'll count tags.sh.
And here.
>> Perfect. Thanks.
>> Yep. No worries.
Why did I mute myself? I'm the
instructor. Okay.
So, now
we can be confident that we're able to
create a script. Now, we're going to
really
start to uh give the script a little
more power. And that's by using
something uh called a loop. And you can
think of loops as as a routine that's
contained within the script. I mean, the
script is a set of instructions. If
there's a part of the script that you
want to be run multiple times, that's
when you would use a loop.
And in order to construct this, we're
going to use some very uh specific uh
language. And in bash uh and the syntax
can vary depending on the programming
language. But in bash, we're going to be
using uh for and do. And so by I'll hit
my up arrow to get the nano command
again, hit enter, and we're back in our
script.
So
let's say that I want to create a loop.
What I'm going to do is first create
some space at the beginning of my script
by pressing enter a couple of times.
The nice thing about um uh these bash
scripts is they're generally agnostic to
spaces and enters uh
most of the time. Uh so I can add as
many new line characters as I want in
here and it's not going to create a
problem.
So as I mentioned the specific language
we're going to use is uh for
and do. And so you can think of these as
the building blocks of our uh of our
loop. So what comes
what comes after four uh are the
parameters that we want to give to our
uh to our loop. So the things that we
want the loop to use and then what comes
after do are the things that we actually
want the loop to do. So the set of
instructions that uh that we want it to
follow.
So to create this for loop, uh what my
goal is to essentially do
do this uh echo and grap uh these echo
and grap operations uh multiple times.
Let's say I want to do it for uh two
files instead of just one.
We can use something uh we can use
something called a uh a variable here
where it think of it like a wild card
but it's it's not a wild card that can
match everything. It's a wild card that
takes on the definitions that you give
it
and hence it is variable and we call it
a variable. We can call this variable
whatever we want but uh for
for instruction sake I will say for file
name file name is our variable.
Um
now we need to tell uh the script what
we want these file names to be. So we're
going to give it a couple of options um
using uh the word in.
and in is telling the program uh to look
for uh to look for an array to give uh
to give to the file name.
So I'm going to give the file name two
things that it can possibly be. Uh the
first can be Atlanta.
GBF
and I'll put another item in the array
here uh which will be London.gbff GBF
which is another one of these genomic
files that we have.
So what we've done here is told the
program that uh for this array of which
we have two file names Atlanta and
London uh to take on that file name and
it's also keeping count of how many
things are in this array. So because our
array has two things in it, Atlanta and
London, it's going to do this loop two
times.
Now we're going to construct the do
section. And fortunately, we have a lot
of this already created uh from our
previous script, but there are some
things that we have to change.
I'm going to navigate down to the echo
line.
And you'll you'll notice that this says
atlant.gbff in plain text. If we were to
run this with uh both the Atlanta and
the London file, um it would say Atlanta
at the beginning of the count both
times. So, what we want to do in this
case is uh take advantage of the fact
that we now have uh access to a
variable.
I'm going to remove Atlanta
and instead I'm going to put
our file name uh variable in within
these quotes. So to uh access a variable
that you've created at the beginning of
your loop, you have to use uh this uh
dollar sign which uh is telling bash to
evaluate that variable uh in in the
place where you've put it.
So I will say file name
I will add a space and then uh close the
quotation marks.
And then so we know this for every uh
iteration through the loop uh we're
first going to echo the name of the file
that we're using.
And now you'll notice in the GP section
of our script uh it also says
atlant.gbff. So we would get the same
result twice. So, in order to fix this,
I'm going to go down, navigating with my
arrow keys.
I'm going to remove Atlanta. GBF,
and similar to above, I'm going to put
uh file name starting with the dollar
sign to tell bash to evaluate it.
File name. And the reason we don't use
quotation marks here uh be is because
uh in the echo line we want it to be a
string. Whereas in this gre line uh we
want we want the the shell to interpret
this as an actual as an actual file not
just not just some text.
Okay. I will go to the end of this line
by hitting end on my keyboard. I
accidentally hit page down which is why
I jumped down. And in order to finish
our loop and tell it that we're done, we
just simply type done.
I will save this by hitting control O.
Uh we will write it to the same script
and I can exit. So now if I've done this
correctly, if I type bash and count
tags,
which we have just updated with our
loop,
it now tells us the counts of both the
atlant.gbff
file with the unique tags and the
London.gbff file with unique tags. And
we can tell that our variables worked
because um the file name uh that we've
output with the echo portion is
different and the counts are different
uh between uh the results of our GP
line.
So that was a lot to take in all at
once. Do we have any any questions from
the group
or any things that I can clarify or
explain a little bit better?
Okay.
>> I have a question about the um the
unique
>> Yep.
>> So, will that work if it's if you have
more than two identical um numbers in a
row? Let's say if you have three or
four, would it also just give you the
unique ones?
>> Yep, it absolutely would. So, um, I can
I'll make a quick test file here. Let's
at this test.txt.
Let's say one one one g3
and I will get D or control D to exit
cat. Uh, so now if we look inside
test.txt dxt with cat
and without using the uh arrow
we can see these numbers are here. If I
wanted to
use the unique command now uh
you can see that it uh it it was able to
remove all of the consecutive ones and
keep only one instance of uh of each
number. And so it would do the same
thing for the tags or for text.
>> Great. Thanks.
>> Yep.
Uh I will remove this test file and
clear my screen.
Okay.
What do we have going on now?
Great. So quickly inspecting our script.
I will use head in this case. uh count
tags.sh.
Now, because I used head and I'm not in
nano, I don't get the nice color
coordination. Um, but that's okay. Uh,
we can see that the file names that
we're using are actually hardcoded into
this loop. So, so far, uh, we're only
able to use this loop for files called
Atlanta.gbf or London.gbff.
If we wanted to use another two files,
we would have to go in and change the
script each time or we can use uh
another uh another set of special
variables that are included in bash uh
which I will demonstrate now.
So, we'll go back into editing our count
tags uh file with nano.
And I'm specifically looking at the uh
uh the first line. So, for file name,
we're going to keep that the same
because that's okay. I'm going to use my
delete key to remove uh Atlanta and
London.
And I'm going to use another another uh
couple of variables here. And so
in bash there are a couple of variables
that are intrinsic to the shell. And so
an example of this is
the variable one and the variable two.
And what these uh what these are telling
our script
is to look for when we when we ask uh
the shell to run our program to look for
the argument in position one or the
first position after we name the script
and position two after we name the
script.
So to demonstrate how this works, I will
save our script. Let's get out of here
with Crl X. And now if I bash count
tags.sh,
I can give it to different file names.
Now I've forgotten what the file names
are. So I'm going to hit ls
to see what's in this folder. And so
somewhat arbitrarily, I will do bash
counts.sh.
Let's do Nevada. And you can tab
complete when you're doing this as well,
uh, when you're adding arguments to your
program. So I'll tab complete Nevada and
I will tab complete Texas.
And so now we know our program is
looking for the uh the arguments in
position one and position two uh after
uh we tell it we're running count tags
sh. So if I hit enter, we see that
Nevada has 5600 and change uh in uh
unique tags and Texas has 5424.
Now, another thing I'll demonstrate is
that because we've only told the script
to look for the first two positions, if
we were to give it a third position, I'm
bringing back the command uh let's say
or a third argument rather, London.gbff.
It's not going to run uh it's not going
to run our loop for that third file
because uh it's not within the
parameters that we set.
Inversely and perhaps uh not
intuitively,
if I have only one of the genome files
and I run our loop, it's going to run
just fine. And so,
uh, depending on how you've written your
script, sometimes this can break things,
but in this case, it works. It just runs
on the single file.
And so we can do this to um run two
files at the same time.
But as I've shown you, maybe you want to
run three. How are we going to do this?
Well, we can use another one of these
special variables in bash. And this one
is a little more akin to a wild card. So
I will go back into count tags through
the nano program.
And for uh the
uh and for the array of things that we
want file name our variable to be able
to take on I'm going to use one of
another one of the special bash uh
variables which is dollar sign telling
uh the the shell to interpret this and
the at sign. And the at is a special
variable which can represent uh any
position uh or any argument uh in the
program you're running. So uh it can be
from 1 to two to 1 2 3 and so on and so
forth. You can put as many
file names as you care to type in here
and it should still work.
So control O to save. I'll press enter
to write it to this file. Crl X to exit.
And I'm going to clear our screen just
to clean things up.
And I will use ls to see what our files
are.
So because we've made our script now
able to accept any number of arguments,
we can use one of the wild cards I've
shown you before. So if I run our bash
script uh count tags.sh
for for
an argument I can use this star
and then period orgff
which will match all of the file names
that you see above this line uh from
Atlanta to Texas uh that end in the GBF
uh extension here.
So now that we've modified our script,
when I press enter, it's going to work
its way through that loop and uh for
each of the files in the directory uh
that match this regular expression. Uh
we can see now that the script has
counted the number of unique tags within
that file.
Okay. Um, that was throwing a couple
bigger concepts at you rather quickly.
Uh, do we have any questions or is there
anything I could go over again?
All right. Um
there are only a couple things that I
want to
uh demonstrate to uh finish up this
module. The first is uh the idea of
comments.
And so if we are working in this uh nano
editor on our counts or on our account
tag script, can we include the GB FFF in
the bash script?
That's a good question. We can try it. I
expect it's not going to work and I
should be able to explain why, but we
can try it.
Let's nano count tags.sh SH
and so
if we do
GBF
here and we can save it. Uh control O uh
file name to write count tagsh enter and
we'll exit. I'm going to run this script
again by hitting up arrow a couple times
till I see the command I want. Uh so I
want to bash run count tags.sh SH was
bash matching all the GBF files. Let's
see what happens.
Okay, something happened. Let's see if
we can figure out what it's trying to
tell us.
I think. Okay.
So,
I think what happened here
is that um this created uh this created
an array of all of the GBF files that uh
that are in this directory. But in the
last item of the array, which was the
Texas.gbff file name, bash uh appended
this extra GBF string. So if I get out
of nano bytrl x, we can see that uh from
this error here, the script was looking
for Texas.gbff.
GBF. This isn't necessarily a behavior I
would have expected.
Could you do something?
I think you probably could.
Okay, let's try it. We have a minute.
Yeah. So,
um I'm going to combine
uh
or yes for file name in star gbff as
David just said this would work. Could
you do something like uh dollar sign add
and dollar sign gbff? I believe you
could. And I think what this is going to
do is run every file twice. But we can
try it. and then
see if we can figure out why. So I will
save this and get out of here and we can
bash it again.
Right. Okay. So we can see that it
worked through the loop twice. We
started at Atlanta, went down to Texas,
and then Atlanta all the way through to
Texas again. And the reason this
happened is um
what we've done here is after the word
in we are creating an array of things to
give to uh to give to the file name
variable.
when um when we use the dollar sign at
to match the GBF in uh in our directory
that's creating one part of the array
where you get each of the file names and
then in addition to that if we
hardcodegF
into our script uh it uh it's creating a
second array kind of that is
again contains all of the file names
names that are within the uh within the
directory you're working in. Now, I
mean, if you were working in a directory
with no GBF files, uh this wouldn't uh
give you anything. Um but because we are
uh it essentially created the first
array from the wild card that we gave
the program and the second array
from being hard-coded in there looking
for those GBF files.
If we hardcoded just GBF files in here,
I'll save this.
Oh, it's the wrong button.
If I run the script again, it should
only run once, right?
And if I take out the wild card here,
right, it knows to look for GBF files
just with just from the script.
Okay.
I'm going to put this back to
uh dollar sign at for that special wild
card.
And what I'm going to do now is
introduce the idea of a comment. And a
comment are things that you can add to
your scripts to help uh yourself better
understand them, to help anyone who's
reading them better understand them. and
you can use it to have code in there
that you may be working on but you don't
necessarily want to run right then.
Generally, it's bad practice to leave a
[snorts] lot of code commented out. So,
don't do that. Uh do as I say, not as I
do. But for instance, if for every time
in our loop, uh
let's say
I'll add another echo here. I'll echo
with a new line. Something I think to do
in the loop.
And I will save this. Exit with control
X. We're going to clear our screen. And
then now if I bash app tags.sh SH uh
matching all of our GVF files in this
directory.
It's adding I'm doing a loop to the
beginning of each of the
uh each of the lines of the output of
our standard out.
So
count tags.sh
if I don't want it to do that. Oh,
I said something wrong earlier. By
default, echo gives you a new line and
the dash n tells it not to do a new
line.
I think I told you the inverse earlier.
Anyway, um if instead we didn't want it
to give us this message every time, we
can use the hashtag character and a
space. And this creates a comment. And a
comment is something when when the when
the
when the kernel sees uh the hashtag, it
just decides, oh, this isn't for me. I'm
not going to read it. I'm not going to
interpret it.
So now that our comment is in there, if
I save this file and exit,
and then we run the command again with
bash,
we can see now that that line that was
originally outputting the extra text uh
is no longer being interpreted because
um there because the I'm doing a loop
text isn't in our final output. And so
you can leave comments wherever you want
in your code. Uh as long as it's not at
the front. You could leave it for
instance
here at the end of this echol line and I
want to say uh this outputs the file
name.
I will save it and exit. Similarly, uh
if I run the bash program again,
you'll see there's not the program h
excuse me, the program hasn't changed
because as soon as it sees the hashtag,
it's reading it line by line, character
by character, left to right. As soon as
it sees the uh as soon as it sees the
hashtag, uh the kernel says, "This is a
comment. I'm not going to bother with
it."
The last thing I'll show you is how to
uh convert this into an executable
script. And so we've been executing it
by telling the shell that we want to run
it with bash. Um but there is a
shorthand for running scripts. Um which
is a dot and a slash. And so for exec
for things that are executable, which
I'll show you how to create in a moment,
this is shorthand for I want to run this
thing. So, it'll say you typing bash uh
every time. If you are trying to run a
script with uh something,
excuse me, that exists in a file path
that's far away, it can be annoying to
have to uh type that every time before
your program.
So, we're going to first
change the permissions of this uh of our
script, our account tags.sh sh script.
We're going to do this with a uh a
program called chmod
to change the permissions.
I'll quickly show you the manual for
chmod.
Change file mode bits. We can see that
uh ch takes options and then uh is
looking for a file.
It changes according to the mode. Um
there are different ways that we can
feed uh chod uh uh certain parameters.
Uh but the way that I'm going to
demonstrate it is not shown in this
manual. Annoyingly,
I'm going to use chod.
I'm going to use this argument plus x.
This is slightly different than a flag
in that this is a specific um this is a
specific argument that's specific. This
is an argument that's specific to the
chod program. Plus x is short for um uh
plus as in add in I want to make it do
this thing and the x stands for
executable.
So chod I'm changing the permissions. I
want to make the thing executable. What
do I want to make executable? That's
going to be our count tags.sh
script.
Now, because we're in a bash in Oh, and
once you do this, if we list our
directory, you can see that count
tags.sh is now green as opposed to uh
earlier when it was uh just uh it looked
like a text file to the shell. So it was
it had white flavor text. This can
differ between uh your uh your shell
environment or your console. Uh but in
our case it should be green.
So to execute this now I can use that
shortcut I showed you earlier which is
the dot and the slash. And I will say
count tags.sh.
And this might work. This should work.
I'll hit enter.
It didn't work. The reason it didn't
work is because the shell is again uh
agnostic to file types. You and I know
that this is a bash script because it
ends insh, but the computer doesn't know
that. So, one final thing we have to do
uh is give the computer some information
as to how it's supposed to work with
this file if we don't specify bash in
the command we use to uh run the
program. So, one last time, we're going
to nano the count tags program
and I'm going to add an important piece
of information to the top of the file
here. So, first I'll press enter a
couple times. and I'll use my up arrow
to go back to the top. Um, this is
something that has to be uh at the top
of the file. I'm going to add something
called a shebang. That's short for
hashtag and exclamation point like
hashbang exclamation point loud. Um, and
now I need to tell the shell
uh what uh what language to use to
interpret this uh this program that
we've written.
So um
the bash
the bash executables are stored in a
place called /bin /bash.
This is something that we can uh this is
something we can add to the top of the
file.
I will save it with control o hit enter.
Uh exit this with control or controll x.
And now if I try doing the dot slash
notation again for count tags.sh.
I think the reason it didn't work last
time is because I didn't give it any
arguments. Someone should have caught me
on that.
I think someone did was just being too
polite to say anything. GB FFF. Uh we
will match all things ending in GBF. And
now uh and now our script works
properly. Because this is going to
bother me, I'm going to back back in and
see if removing uh the shebang line is
going to do anything very quickly.
Aha, it would have worked. And the
reason it would have worked is because
we are in a bash environment. Uh but
sometimes you're going to be using other
languages. This could include uh R,
which we'll be using in the workshop.
You may be using pearl from time to time
which is common to combine uh in some
bash programs. Uh you could be using
Python. Um you need to tell
uh you need your script to tell the uh
to tell the kernel how to read your
program.