< Return to Video

Lecture 2: Shell Tools and Scripting (2020)

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

more » « less
Video Language:
English
Duration:
48:56

English subtitles

Revisions