-
Okay, welcome back.
-
Today we're gonna cover a couple separate
-
two main topics related to the shell.
-
First, we're gonna do some kind of shell
scripting, mainly related to bash,
-
which is the shell that most of you will start
-
in Mac, or like in most Linux systems,
that's the default shell.
-
And it's also kind of backward compatible through
other shells like zsh, it's pretty nice.
-
And then we're gonna cover some other shell
tools that are really convenient,
-
so you avoid doing really repetitive tasks,
-
like looking for some piece of code
-
or for some elusive file.
-
And there are already really
nice built-in commands
-
that will really help you to do those things.
-
So yesterday we already kind of introduced
-
you to the shell and some of it's quirks,
-
and like how you start executing commands,
-
redirecting them.
-
Today, we're going to kind of cover more about
-
the syntax of the variables, the control flow,
-
functions of the shell.
-
So for example, once you drop
into a shell, say you want to
-
define a variable, which is
one of the first things you
-
learn to do in a programming language.
-
Here you could do something like foo equals bar.
-
And now we can access the value
of foo by doing "$foo".
-
And that's bar, perfect.
-
One quirk that you need to be aware of is that
-
spaces are really critical when
you're dealing with bash.
-
Mainly because spaces are reserved, and
that will be for separating arguments.
-
So, for example, something like foo equals bar
-
won't work, and the shell is gonna
tell you why it's not working.
-
It's because the foo command is not
working, like foo is non-existent.
-
And here what is actually happening,
we're not assigning foo to bar,
-
what is happening is we're
calling the foo program
-
with the first argument "=" and
the second argument "bar".
-
And in general, whenever you are having
some issues, like some files with spaces
-
you will need to be careful about that.
-
You need to be careful about quoting strings.
-
So, going into that, how you do strings in bash.
There are two ways that you can define a string:
-
You can define strings using double quotes
and you can define strings using single,
-
sorry,
-
using single quotes.
-
However, for literal strings they are equivalent,
-
but for the rest they are not equivalent.
-
So, for example, if we do value is $foo,
-
the $foo has been expanded like
a string, substituted to the
-
value of the foo variable in the shell.
-
Whereas if we do this with a simple quote,
we are just getting the $foo as it is
-
and single quotes won't be replacing. Again,
-
it's really easy to write a script, assume that
this is kind of like Python, that you might be
-
more familiar with, and not realize all that.
-
And this is the way you will assign variables.
-
Then bash also has control flow
techniques that we'll see later,
-
like for loops, while loops, and one main
thing is you can define functions.
-
We can access a function I have defined here.
-
Here we have the MCD function, that
has been defined, and the thing is
-
so far, we have just kind of seen how
to execute several commands by piping
-
into them, kind of saw that briefly yesterday.
-
But a lot of times you want to do first
one thing and then another thing.
-
And that's kind of like the
-
sequential execution that we get here.
-
Here, for example, we're
calling the MCD function.
-
We, first,
-
are calling the makedir command,
which is creating this directory.
-
Here, $1 is like a special variable.
-
This is the way that bash works,
-
whereas in other scripting languages
there will be like argv,
-
the first item of the array argv
will contain the argument.
-
In bash it's $1. And in general, a lot
-
of things in bash will be dollar something
-
and will be reserved, we will
be seeing more examples later.
-
And once we have created the folder,
we CD into that folder,
-
which is kind of a fairly common
pattern that you will see.
-
We will actually type this directly
into our shell, and it will work and
-
it will define this function. But sometimes
it's nicer to write things in a file.
-
What we can do is we can source
this. And that will
-
execute this script in our shell and load it.
-
So now it looks like nothing happened,
but now the MCD function has
-
been defined in our shell. So
we can now for example do
-
MCD test, and now we move from
the tools directory to the test
-
directory. We both created the
folder and we moved into it.
-
What else. So a result is...
-
We can access the first argument with $1.
-
There's a lot more reserved commands,
-
for example $0 will be the name of the script,
-
$2 through $9 will be the second
through the ninth arguments
-
that the bash script takes.
Some of these reserved
-
keywords can be directly used
in the shell, so for example
-
$? will get you the error code
from the previous command,
-
which I'll also explain briefly.
-
But for example, $_ will get
you the last argument of the
-
previous command. So another way
we could have done this is
-
we could have said like "mkdir test"
-
and instead of rewriting test, we
can access that last argument
-
as part of the (previous command), using $_
-
like, that will be replaced with
test and now we go into test.
-
There are a lot of them, you
should familiarize with them.
-
Another one I often use is called "bang
bang" ("!!"), you will run into this
-
whenever you, for example, are trying
to create something and you don't have
-
enough permissions. Then, you can do "sudo !!"
-
and then that will replace the command in
-
there and now you can just try doing
-
that. And now it will prompt you for a password,
-
because you have sudo permissions.
-
Before, I mentioned the, kind
of the error command.
-
Yesterday we saw that, in general, there are
-
different ways a process can communicate
-
with other processes or commands.
-
We mentioned the standard
input, which also was like
-
getting stuff through the standard input,
-
putting stuff into the standard output.
-
There are a couple more interesting
things, there's also like a
-
standard error, a stream where you write errors
-
that happen with your program and you don't
want to pollute the standard output.
-
There's also the error code,
which is like a general
-
thing in a lot of programming languages,
-
some way of reporting how the
entire run of something went.
-
So if we do
-
something like echo hello and we
-
query for the value, it's zero. And it's zero
-
because everything went okay and there
-
weren't any issues. And a zero exit code is
-
the same as you will get in a language
-
like C, like 0 means everything
went fine, there were no errors.
-
However, sometimes things won't work.
-
Sometimes, like if we try to grep
for foobar in our MCD script,
-
and now we check for that
value, it's 1. And that's
-
because we tried to search for the foobar
-
string in the MCD script and it wasn't there.
-
So grep doesn't print anything, but
-
let us know that things didn't work by
-
giving us a 1 error code.
-
There are some interesting commands like
-
"true", for example, will always have a zero
-
error code, and false will always
have a one error code.
-
Then there are like
-
these logical operators that you can use
-
to do some sort of conditionals.
For example, one way...
-
you also have IF's and ELSE's, that
we will see later, but you can do
-
something like "false", and echo "Oops fail".
-
So here we have two commands connected
by this OR operator.
-
What bash is gonna do here, it's
gonna execute the first one
-
and if the first one didn't work, then it's
-
gonna execute the second one. So here we get it,
-
because it's gonna try to do a logical
OR. If the first one didn't have
-
a zero error code, it's gonna try to
do the second one. Similarly, if we
-
instead of use "false", we
use something like "true",
-
since true will have a zero error code, then the
-
second one will be short-circuited and
-
it won't be printed.
-
Similarly, we have an AND
operator which will only
-
execute the second part if the first one
-
ran without errors.
-
And the same thing will happen.
-
If the first one fails, then the second
part of this thing won't be executed.
-
Kind of not exactly related to that, but
another thing that you will see is
-
that no matter what you execute,
then you can concatenate
-
commands using a semicolon in the same line,
-
and that will always print.
-
Beyond that, what we haven't
seen, for example, is how
-
you go about getting the output
of a command into a variable.
-
And the way we can do that is
doing something like this.
-
What we're doing here is we're getting
the output of the PWD command,
-
which is just printing the
present working directory
-
where we are right now.
-
And then we're storing that
into the foo variable.
-
So we do that and then we ask
for foo, we view our string.
-
More generally, we can do this thing
called command substitution
-
by putting it into any string.
-
And since we're using double quotes
instead of single quotes
-
that thing will be expanded and
-
it will tell us that we are
in this working folder.
-
Another interesting thing is, right now,
what this is expanding to is a string
-
instead of
-
It's just expanding as a string.
-
Another nifty and lesser known tool
is called process substitution,
-
which is kind of similar. What it will do...
-
it will, here for example, the "<(",
some command and another parenthesis,
-
what that will do is: that will execute,
that will get the output to
-
kind of like a temporary file and it will
give the file handle to the command.
-
So here what we're doing is we're getting...
-
we're LS'ing the directory, putting
it into a temporary file,
-
doing the same thing for the
parent folder and then
-
we're concatenating both files. And this
-
will, may be really handy, because
some commands instead of expecting
-
the input coming from the stdin,
they are expecting things to
-
come from some file that is giving
some of the arguments.
-
So we get both things concatenated.
-
I think so far there's been a lot of
information, let's see a simple,
-
an example script where we
see a few of these things.
-
So for example here we have a string and we
-
have this $date. So $date is a program.
-
Again there's a lot of programs
in UNIX you will kind of slowly
-
familiarize with a lot of them.
-
Date just prints what the current date is
and you can specify different formats.
-
Then, we have these $0 here. $0 is the name
-
of the script that we're running.
-
Then we have $#, that's the number
of arguments that we are giving
-
to the command, and then $$ is the process
ID of this command that is running.
-
Again, there's a lot of these dollar
things, they're not intuitive
-
because they don't have like a mnemonic
-
way of remembering, maybe, $#. But
-
it can be... you will just be
-
seeing them and getting familiar with them.
-
Here we have this $@, and that will
expand to all the arguments.
-
So, instead of having to assume that,
-
maybe say, we have three arguments
and writing $1, $2, $3,
-
if we don't know how many arguments we
can put all those arguments there.
-
And that has been given to a
for loop. And the for loop
-
will, in time, get the file variable
-
and it will be giving each one of the arguments.
-
So what we're doing is, for every
one of the arguments we're giving.
-
Then, in the next line we're running the
-
grep command which is just search for
a substring in some file and we're
-
searching for the string foobar in the file.
-
Here, we have put the variable
that the file took, to expand.
-
And yesterday we saw that if we care
about the output of a program, we can
-
redirect it to somewhere, to save it
or to connect it to some other file.
-
But sometimes you want the opposite.
-
Sometimes, here for example, we care...
-
we're gonna care about the error code. About
this script, we're gonna care whether the
-
grep ran successfully or it didn't.
-
So we can actually discard
entirely what the output...
-
like both the standard output and the
standard error of the grep command.
-
And what we're doing is we're
-
redirecting the output to /dev/null which
-
is kind of like a special device in UNIX
-
systems where you can like write and
-
it will be discarded. Like you can
-
write no matter how much you want,
-
there, and it will be discarded.
And here's the ">" symbol
-
that we saw yesterday for redirecting
output. Here you have a "2>"
-
and, as some of you might have
-
guessed by now, this is for redirecting the
-
standard error, because those those two
-
streams are separate, and you kind of have to
-
tell bash what to do with each one of them.
-
So here, we run, we check if the file has
-
foobar, and if the file has foobar then it's
-
going to have a zero code. If it
-
doesn't have foobar, it's gonna have a
-
nonzero error code. So that's exactly what we
-
check. In this if part of the command we
-
say "get me the error code". Again, this $?
-
And then we have a comparison operator
-
which is "-ne", for "non equal". And some
-
other programming languages
will have "==", "!=", these
-
symbols. In bash there's
-
like a reserved set of comparisons and
-
it's mainly because there's a lot of
-
things you might want to test for when
-
you're in the shell. Here for example
-
we're just checking for two values, two
integer values, being the same. Or for
-
example here, the "-F" check will let
-
us know if a file exists, which is
-
something that you will run into very,
-
very commonly. I'm going back to the
-
example. Then, what happens when we
-
if the file did not have
foobar, like there was a
-
nonzero error code, then we print
-
"this file doesn't have any foobar,
-
we're going to add one". And what we do is
-
we echo this "# foobar", hoping this
-
is a comment to the file and then we're
-
using the operator ">>" to append at the end of
-
the file. Here since the file has
-
been fed through the script, and we don't
know it beforehand, we have to substitute
-
the variable of the filename. We can
actually run this. We already have
-
correct permissions in this script and
-
we can give a few examples. We have a
few files in this folder, "mcd" is the
-
one we saw at the beginning for the MCD
-
function, some other "script" function and
-
we can even feed the own script to itself
to check if it has foobar in it.
-
And we run it and first we can
see that there's different
-
variables that we saw, that have been
-
successfully expanded. We have the date, that has
-
been replaced to the current time, then
-
we're running this program, with three
-
arguments, this randomized PID, and then
-
it's telling us MCD doesn't have any
-
foobar, so we are adding a new one,
-
and this script file doesn't
-
have one. So now for example let's look at MCD
-
and it has the comment that we were looking for.
-
One other thing to know when you're
executing scripts is that
-
here we have like three completely
-
different arguments but very commonly
-
you will be giving arguments that
-
can be more succinctly given in some way.
-
So for example here if we wanted to
-
refer to all the ".sh" scripts we
-
could just do something like "ls *.sh"
-
and this is a way of filename expansion
that most shells have
-
that's called "globbing". Here, as you
-
might expect, this is gonna say
-
anything that has any kind of sort of
-
characters and ends up with "sh".
-
Unsurprisingly, we get "example.sh"
and "mcd.sh". We also have these
-
"project1" and "project2", and if there
-
were like a... we can do a
"project42", for example
-
And now if we just want to refer
to the projects that have
-
a single character, but not two characters
-
afterwards, like any other characters,
-
we can use the question mark. So "?"
will expand to only a single one.
-
And we get, LS'ing, first
-
"project1" and then "project2".
-
In general, globbing can be very powerful.
You can also combine it.
-
A common pattern is to use what
is called curly braces.
-
So let's say we have an image,
that we have in this folder
-
and we want to convert this image from PNG to JPG
-
or we could maybe copy it, or...
-
it's a really common pattern, to have
two or more arguments that are
-
fairly similar and you want to do something
with them as arguments to some command.
-
You could do it this way, or more
succinctly, you can just do
-
"image.{png,jpg}"
-
And here, I'm getting some color feedback,
but what this will do, is
-
it'll expand into the line above.
-
Actually, I can ask zsh to do that for
me. And that what's happening here.
-
This is really powerful. So for example
-
you can do something like... we could do...
-
"touch" on a bunch of foo's, and
all of this will be expanded.
-
You can also do it at several levels
and you will do the Cartesian...
-
if we have something like this,
we have one group here, "{1,2}"
-
and then here there's "{1,2,3}",
and this is going to do
-
the Cartesian product of these
-
two expansions and it will expand
into all these things,
-
that we can quickly "touch".
-
You can also combine the asterisk
glob with the curly braces glob.
-
You can even use kind of ranges.
Like, we can do "mkdir"
-
and we create the "foo" and the
"bar" directories, and then we
-
can do something along these lines. This
-
is going to expand to "fooa", "foob"...
-
like all these combinations, through "j", and
-
then the same for "bar". I haven't
-
really tested it... but yeah, we're getting
all these combinations that we
-
can "touch". And now, if we touch something
-
that is different between these
two [directories], we
-
can again showcase the process
substitution that we saw
-
earlier. Say we want to check what
files are different between these
-
two folders. For us it's obvious,
we just saw it, it's X and Y,
-
but we can ask the shell to do
this "diff" for us between the
-
output of one LS and the other LS.
-
Unsurprisingly we're getting: X is
-
only in the first folder and Y is
-
only in the second folder. What is more
-
is, right now, we have only seen
bash scripts. If you like other
-
scripts, like for some tasks bash
is probably not the best,
-
it can be tricky. You can actually
write scripts that
-
interact with the shell implemented in a lot
-
of different languages. So for
example, let's see here a
-
Python script that has a magic line at the
-
beginning that I'm not explaining for now.
-
Then we have "import sys",
-
it's kind of like... Python is not,
by default, trying to interact
-
with the shell so you will have to import
-
some library. And then we're doing a
-
really silly thing of just iterating
-
over "sys.argv[1:]".
-
"sys.argv" is kind of similar to what
in bash we're getting as $0, $1, &c.
-
Like the vector of the arguments, we're
printing it in the reversed order.
-
And the magic line at the beginning is
-
called a shebang and is the way that the
-
shell will know how to run this program.
-
You can always do something like
-
"python script.py", and then "a b c" and that
-
will work, always, like that. But
-
what if we want to make this to be
-
executable from the shell? The way the
-
shell knows that it has to use python as the
-
interpreter to run this file is using
-
that first line. And that first line is
-
giving it the path to where that thing lives.
-
However, you might not know.
-
Like, different machines will have probably
-
different places where they put python
-
and you might not want to assume where
-
python is installed, or any other interpreter.
-
So one thing that you can do is use the
-
"env" command.
-
You can also give arguments in the shebang, so
-
what we're doing here is specifying
-
run the "env" command, that is for pretty much every
system, there are some exceptions, but like for
-
pretty much every system it's is in
-
"usr/bin", where a lot of binaries live,
-
and then we're calling it with the
-
argument "python". And then that will make
-
use of the path environment variable
-
that we saw in the first lecture. It's
-
gonna search in that path for the Python
-
binary and then it's gonna use that to
-
interpret this file. And that will make
-
this more portable so it can be run in
-
my machine, and your machine
and some other machine.
-
Another thing is that the bash is not
-
really like modern, it was
-
developed a while ago. And sometimes
-
it can be tricky to debug. By
-
default, and the ways it will fail
-
sometimes are intuitive like the way we
-
saw before of like foo command not
-
existing, sometimes it's not. So there's
-
like a really nifty tool that we have
-
linked in the lecture notes, which is called
-
"shellcheck", that will kind of give you
-
both warnings and syntactic errors
-
and other things that you might
not have quoted properly,
-
or you might have misplaced spaces in
-
your files. So for example for
extremely simple "mcd.sh"
-
file we're getting a couple
-
of errors saying hey, surprisingly,
-
we're missing a shebang, like this
-
might not interpret it correctly if you're
-
it at a different system. Also, this
-
CD is taking a command and it might not
-
expand properly so instead of using CD
-
you might want to use something like CD
-
and then an OR and then an "exit". We go
-
back to what we explained earlier, what
-
this will do is like if the
-
CD doesn't end correctly, you cannot CD
-
into the folder because either you
-
don't have permissions, it doesn't exist...
-
That will give a nonzero error
-
command, so you will execute exit
-
and that will stop the script
-
instead of continue executing as if
-
you were in a place that you are
-
actually not in. And actually
I haven't tested, but I
-
think we can check for "example.sh"
-
and here we're getting that we should be
-
checking the exit code in a
different way, because it's
-
probably not the best way, doing it this
-
way. One last remark I want to make
-
is that when you're writing bash scripts
-
or functions for that matter,
-
there's kind of a difference between
-
writing bash scripts in isolation like a
-
thing that you're gonna run, and a thing
-
that you're gonna load into your shell.
-
We will see some of this in the command
-
line environment lecture, where we will kind of
-
be tooling with the bashrc and the
sshrc. But in general, if you make
-
changes to for example where you are,
-
like if you CD into a bash script and you
-
just execute that bash script, it won't CD
-
into the shell are right now. But if you
-
have loaded the code directly into
-
your shell, for example you load...
-
you source the function and then you execute
-
the function then you will get those
-
side effects. And the same goes for
-
defining variables into the shell.
-
Now I'm going to talk about some
tools that I think are nifty when
-
working with the shell. The first was
-
also briefly introduced yesterday.
-
How do you know what flags, or like
-
what exact commands are. Like how I am
-
supposed to know that LS minus L will list
the files in a list format, or that
-
if I do "move - i", it's gonna like prom me
-
for stuff. For that what you have is the "man"
-
command. And the man command will kind of
-
have like a lot of information of how
-
will you go about... so for example here it
-
will explain for the "-i" flag, there are
-
all these options you can do. That's
-
actually pretty useful and it will work
-
not only for really simple commands
that come packaged with your OS
-
but will also work with some tools
that you install from the internet
-
for example, if the person that did the
-
installation made it so that the man
-
package were also installed. So for example
-
a tool that we're gonna cover in a bit
-
which is called "ripgrep" and
is called with RG, this didn't
-
come with my system but it has installed
-
its own man page and I have it here and
-
I can access it. For some commands the
-
man page is useful but sometimes it can be
-
tricky to decipher because it's more
-
kind of a documentation and a
-
description of all the things the tool
-
can do. Sometimes it will have
-
examples but sometimes not, and sometimes
-
the tool can do a lot of things so a
-
couple of good tools that I use commonly
-
are "convert" or "ffmpeg", which deal
with images and video respectively and
-
the man pages are like enormous. So there's
-
one neat tool called "tldr" that
-
you can install and you will have like
-
some nice kind of explanatory examples
-
of how you want to use this command. And you
-
can always Google for this, but I find
-
myself saving going into the
-
browser, looking about some examples and
-
coming back, whereas "tldr" are
-
community contributed and
-
they're fairly useful. Then,
-
the one for "ffmpeg" has a lot of
-
useful examples that are more nicely
-
formatted (if you don't have a huge
-
font size for recording). Or even
-
simple commands like "tar", that have a lot
-
of options that you are combining. So for
-
example, here you can be combining 2, 3...
-
different flags and it can not be
-
obvious, when you want to combine
-
different ones. That's how you
-
would go about finding more about these tools.
On the topic of finding, let's try
-
learning how to find files. You can
-
always go "ls", and like you can go like
-
"ls project1", and
-
keep LS'ing all the way through. But
-
maybe, if we already know that we want
-
to look for all the folders called
-
"src", then there's probably a better command
-
for doing that. And that's "find".
-
Find is the tool that, pretty much comes
with every UNIX system. And find,
-
we're gonna give it... here we're
saying we want to call find in the
-
current folder, remember that "." stands
-
for the current folder, and we want the
-
name to be "src" and we want the type to
be a directory. And by typing that it's
-
gonna recursively go through the current
-
directory and look for all these files,
-
or folders in this case, that match this
pattern. Find has a lot of useful
-
flags. So for example, you can even test
-
for the path to be in a way. Here we're
-
saying we want some number of folders,
-
we don't really care how many folders,
-
and then we care about all the Python
-
scripts, all the things with the extension
".py", that are within a
-
test folder. And we're also checking, just in
-
cases really but we're checking just
-
that it's also a type F, which stands for
-
file. We're getting all these files.
-
You can also use different flags for things
-
that are not the path or the name.
-
You could check things that have been
-
modified ("-mtime" is for the modification
time), things that have been
-
modified in the last day, which is gonna
-
be pretty much everything. So this is gonna print
-
a lot of the files we created and files
-
that were already there. You can even
-
use other things like size, the owner,
-
permissions, you name it. What is even more
-
powerful is, "find" can find stuff
-
but it also can do stuff when you
-
find those files. So we could look for all
-
the files that have a TMP
-
extension, which is a temporary extension, and
-
then, we can tell "find" that
for every one of those files,
-
just execute the "rm" command for them. And
-
that will just be calling "rm" with all
-
these files. So let's first execute it
-
without, and then we execute it with it.
-
Again, as with the command line
-
philosophy, it looks like nothing
-
happened. But since we have
a zero error code, something
-
happened - just that everything went
-
correct and everything is fine. And now,
-
if we look for these files,
they aren't there anymore.
-
Another nice thing about the shell
in general is that there are
-
these tools, but people will keep
-
finding new ways, so alternative
-
ways of writing these tools. It's
nice to know about it. So, for
-
example find if you just want to match
the things that end in "tmp"
-
it can be sometimes weird to do this
thing, it has a long command.
-
There's things like "fd",
-
for example, that is a shorter command
that by default will use regex
-
and will ignore your gitfiles, so you
-
don't even search for them. It
-
will color-code, it will have better
Unicode support... It's nice to
-
know about some of these tools. But, again,
-
the main idea is that if you are aware
that these tools exist, you can
-
save yourself a lot of time from doing
-
kind of menial and repetitive tasks.
-
Another command to bear in mind is like
-
"find". Some of you may be
-
wondering, "find" is probably just
-
actually going through a directory
-
structure and looking for things but
-
what if I'm doing a lot of "finds" a day?
-
Wouldn't it be better, doing kind of
-
a database approach and build an index
first, and then use that index
-
and update it in some way. Well, actually
-
most Unix systems already do it and
-
this is through the "locate" command and
-
the way that the locate will
-
be used... it will just look for paths in
-
your file system that have the substring
-
that you want. I actually don't know if it
will work... Okay, it worked. Let me try to
-
do something like "missing-semester".
-
You're gonna take a while but
-
it found all these files that are somewhere
-
in my file system and since it has
-
built an index already on them, it's much
-
faster. And then, to keep it updated,
-
using the "updatedb" command
that is running through cron,
-
to update this database. Finding files, again, is
-
really useful. Sometimes you're actually concerned
about, not the files themselves,
-
but the content of the files. For that
-
you can use the grep command that we
-
have seen so far. So you could do
-
something like grep foobar in MCD, it's there.
-
What if you want to, again, recursively
search through the current
-
structure and look for more files, right?
-
We don't want to do this manually.
-
We could use "find", and the "-exec", but
-
actually "grep" has the "-R" flag
that will go through the entire
-
directory, here. And it's telling us
-
that oh we have the foobar line in example.sh
-
at these three places and in
-
this other two places in foobar. This can be
-
really convenient. Mainly, the
-
use case for this is you know you have
-
written some code in some programming
-
language, and you know it's somewhere in
-
your file system but you actually don't
-
know. But you can actually quickly search.
-
So for example, I can quickly search
-
for all the Python files that I have in my
-
scratch folder where I used the request library.
-
And if I run this, it's giving me
-
through all these files, exactly in
-
what line it has been found. And here
-
instead of using grep, which is fine,
-
you could also do this, I'm using "ripgrep",
-
which is kind of the same idea but
again trying to bring some more
-
niceties like color coding or file
-
processing and other things. It think it has,
also, unicode support. It's also pretty
-
fast so you are not paying like a
trade-off on this being slower and
-
there's a lot of useful flags. You
-
can say, oh, I actually want to get some
-
context around those results.
-
So I want to get like five
lines of context around
-
that, so you can see where that import
lives and see code around it.
-
Here in the import it's not really useful
-
but like if you're looking for where you
-
use the function, for example, it will
-
be very handy. We can also do things like
-
we can search, for example here,.
-
A more advanced use, we can say,
-
"-u" is for don't ignore hidden files, sometimes
-
you want to be ignoring hidden
files, except if you want to
-
search config files, that are by default
hidden. Then, instead of printing
-
the matches, we're asking to do something
that would be kind of hard, I think,
-
to do with grep, out of my head, which is
-
"I want you to print all the files that
-
don't match the pattern I'm giving you", which
-
may be a weird thing to ask here but
-
then we keep going... And this pattern here
-
is a small regex which is saying
-
at the beginning of the line I have a
-
"#" and a "!", and that's a shebang.
-
Like that, we're searching here for all
-
the files that don't have a shebang
-
and then we're giving it, here,
-
a "-t sh" to only look for "sh"
-
files, because maybe all your
Python or text files are fine
-
without a shebang. And here it's telling us
-
"oh, MCD is obviously missing a shebang"
-
We can even... It has like some
-
nice flags, so for example if we
-
include the "stats" flag
-
it will get all these results but it will
also tell us information about all
-
the things that it searched. For example,
-
the number of matches that it found,
the lines, the file searched,
-
the bytes that it printed, &c.
-
Similar as with "fd", sometimes
it's not as useful
-
using one specific tool or another and
-
in fact, as ripgrep, there are several
other tools. Like "ack",
-
is the original grep alternative that was
-
written. Then the silver searcher,
-
"ag", was another one... and they're all
-
pretty much interchangeable so
-
maybe you're at a system that has one and
-
not the other, just knowing that you can
-
use these things with these tools can be
-
fairly useful. Lastly, I want to cover
-
how you go about, not finding files
or code, but how you go about
-
finding commands that you already
-
some time figured out. The first, obvious
way is just using the up arrow,
-
and slowly going through all your history,
looking for these matches.
-
This is actually not very efficient, as
-
you probably guessed. So the bash
has ways to do this more easily.
-
There is the "history" command, that will
-
print your history. Here I'm in zsh and
it only prints some of my history, but
-
if I say, I want you to print everything
from the beginning of time, it will print
-
everything from the beginning
of whatever this history is.
-
And since this is a lot of results,
-
maybe we care about the ones where we
-
use the "convert" command to go from some
type of file to some other type of file.
-
Some image, sorry. Then, we're getting all
-
these results here, about all the ones
-
that match this substring.
-
Even more, pretty much all shells by default will
-
link "Ctrl+R", the keybinding,
-
to do backward search. Here we
-
have backward search, where we can
-
type "convert" and it's finding the
-
command that we just typed. And if we just
-
keep hitting "Ctrl+R", it will
-
kind of go through these matches and
-
it will let re-execute it
-
in place. Another thing that you can do,
-
related to that, is you can use this
-
really nifty tool called "fzf", which is
-
like a fuzzy finder, like it will...
-
It will let you do kind of
-
like an interactive grep. We could do
-
for example this, where we can cat our
-
example.sh command, that will print
-
print to the standard output, and then we
-
can pipe it through fzf. It's just getting
-
all the lines and then we can
interactively look for the
-
string that we care about. And the nice
-
thing about fzf is that, if you enable
the default bindings, it will bind to
-
your "Ctrl+R" shell execution and now
-
you can quickly and dynamically like
-
look for all the times you try to
convert a favicon in your history.
-
And it's also like fuzzy matching,
whereas like by default in grep
-
or these things you have to write a regex or some
-
expression that will match within here.
-
Here I'm just typing "convert" and "favicon" and
-
it's just trying to do the best scan,
-
doing the match in the lines it has.
-
Lastly, a tool that probably you have
already seen, that I've been using
-
for not retyping these extremely long
-
commands is this "history
substring search", where
-
as I type in my shell,
-
and both F fail to mention but both face
-
which I think was originally introduced,
this concept, and then
-
zsh has a really nice implementation)
-
what it'll let you do is
-
as you type the command, it will
dynamically search back in your
-
history to the same command
that has a common prefix,
-
and then, if you...
-
it will change as the match list stops
-
working and then as you do the
-
right arrow you can select that
command and then re-execute it.
-
We've seen a bunch of stuff... I think I have
-
a few minutes left so I'm going
to cover a couple of tools to do
-
really quick directory listing
and directory navigation.
-
So you can always use the "-R" to recursively
list some directory structure,
-
but that can be suboptimal, I cannot
really make sense of this easily.
-
There's tool called "tree" that will
be the much more friendly form of
-
printing all the stuff, it will
also color code based on...
-
here for example "foo" is blue
because it's a directory and
-
this is red because it has execute permissions.
-
But we can go even further than
that. There's really nice tools
-
like a recent one called "broot" that
will do the same thing but here
-
for example instead of doing
this thing of listing
-
every single file, for example in bar
-
we have these "a" through "j" files,
-
it will say "oh there are more, unlisted here".
-
I can actually start typing and it will again
-
again facily match to the files that are there
-
and I can quickly select them
and navigate through them.
-
So, again, it's good to know that
-
these things exist so you don't
lose a large amount of time
-
going for these files.
-
There are also, I think I have it installed
-
also something more similar to what
you would expect your OS to have,
-
like Nautilus or one of the Mac
finders that have like an
-
interactive input where you can just use your
navigation arrows and quickly explore.
-
It might be overkill but you'll
be surprised how quickly you can
-
make sense of some directory structure
by just navigating through it.
-
And pretty much all of these tools
will let you edit, copy files...
-
if you just look for the options for them.
-
The last addendum is kind of going places.
-
We have "cd", and "cd" is nice, it will get you
-
to a lot of places. But it's pretty handy if
-
you can like quickly go places,
-
either you have been to recently or that
-
you go frequently. And you can do this in
-
many ways there's probably... you can start
-
thinking, oh I can make bookmarks, I can
-
make... I can make aliases in the shell,
-
that we will cover at some point,
-
symlinks... But at this point,
-
programmers have like built all these
-
tools, so programmers have already figured
-
out a really nice way of doing this.
-
One way of doing this is using what is
-
called "auto jump", which I
think is not loaded here...
-
Okay, don't worry. I will cover it
in the command line environment.
-
I think it's because I disabled
the "Ctrl+R" and that also
-
affected other parts of the script.
I think at this point if anyone has
-
any questions that are related to this,
I'll be more than happy to answer
-
them, if anything was left unclear.
-
Otherwise, a there's a bunch of
exercises that we wrote, kind of
-
touching on these topics and we
encourage you to try them and
-
come to office hours, where we can help
-
you figure out how to do them, or some
bash quirks that are not clear.