Okay, can everyone hear me okay?
Okay, so welcome back.
I'm gonna address a couple of items in kind of the administratrivia.
With the end of the first week,
we sent an email, noticing you that
we have uploaded the videos for the first week, so you can now find them online.
They have all the screen recordings for the things that we were doing, so you can go back to them.
Look if you're were confused about if we did something quick and, again,
feel free to ask us any questions if anything in the lecture notes is not clear. We also sent you a
survey so you can give us feedback about what was not clear,
what items you would want a more thorough explanation or
just any other item, if you're finding the exercises too hard, too easy,
go into that URL and we'll really
appreciate getting that feedback, because that will make the course better
for the remaining lectures and for future iterations of the course.
With that out of the way
Oh, and we're gonna try to upload the videos in a more timely manner.
We don't want to kind of wait until the end of the week for that. So keep tuned for that.
That out of the way,
now I'm gonna
This lecture's called command-line environment and we're
going to cover a few different topics. So the
main topics we're gonna
cover, so you can keep track,
it's probably better here,
keep track of what I'm talking.
The first is gonna be job control.
The second one is going to be
terminal multiplexers.
Then I'm going to explain what dotfiles are and how to configure your shell.
And lastly, how to efficiently work with remote machines. So if things are not
fully clear, kind of keep the structure.
They all kind of interact in some way, of how you use your terminal,
but they are somewhat separate topics, so keep that in mind.
So let's go with job control. So far we have been using the shell in a very, kind of
mono-command way. Like, you execute a command and then
the command executes, then you get some output, and that's all about what you can do.
And if you want to run several things, it's not clear
how you will do it. Or if you want to stop the execution of a program, it's again,
like how do I know how to stop a program?
Let's showcase this with a command called sleep.
Sleep is a command that takes an argument,
and that argument is going to be an integer number, and it will sleep.
It will just kind of be there, on the background, for that many seconds.
So if we do something like sleep 20, this process is gonna be sleeping for 20 seconds.
But we don't want to wait 20 seconds for the command to complete.
So what we can do is type "Ctrl+C".
By typing "Ctrl+C"
We can see that, here, the terminal let us know,
and it's part of the syntax that we covered in the editors / Vim lecture,
that we typed "Ctrl+C" and it stopped the execution of the process.
What is actually going on here
is that this is using a UNIX communication mechanism called signals.
When we type "Ctrl+C",
what the terminal did for us, or the shell did for us,
is send a signal called SIGINT,
that stands for SIGnal INTerrupt, that tells the program to stop itself.
And there are many, many, many signals of this kind. If you do man signal,
and just go down a little bit, here you have a list of them.
They all have number identifiers,
they have kind of a short name and you can find a description.
So for example, the one I have just described is here, number 2, SIGINT.
This is the signal that a terminal will send to a program when it wants to interrupt its execution.
A few more to be familiar with
is SIGQUIT, this is
again, if you work from a terminal and you want to quit the execution of a program.
For most programs it will do the same thing,
but we're gonna showcase now a program which will be different,
and this is the signal that will be sent.
It can be confusing sometimes. Looking at these signals, for example, the SIGTERM is
for most cases equivalent to SIGINT and SIGQUIT
but it's just when it's not sent through a terminal.
A few more that we're gonna
cover is SIGHUP, it's when there's like a hang-up in the terminal.
So for example, when you are in your terminal, if you close your terminal
and there are still things running in the terminal,
that's the signal that the program is gonna send
to all the processes to tell that they should close,
like there was a hang-up in the command line communication
and they should close now.
Signals can do more things than just stopping, interrupting programs and asking them to finish.
You can for example use the
SIGSTOP to pause the execution of the program, and then you can use the
SIGCONT command for continuing, to continue the execution of the program at a point later in time.
Since all of this might be slightly too abstract, let's see a few examples.
First, let's showcase a
Python program. I'm going to very quickly go through the program.
This is a Python program,
that like most python programs,
is importing this signal library and
is defining this handler here. And this handler is writing,
"Oh, I got a SIGINT, but I'm not gonna stop here".
And after that,
we tell Python that we want this program, when it gets a SIGINT, to stop.
The rest of the program is a very silly program that is just going to be printing numbers.
So let's see this in action.
We do Python SIGINT.
And it's counting. We try doing "Ctrl+C", this sends a SIGINT,
but the program didn't actually stop. This is because we have a way in the program of
dealing with this exception, and we didn't want to exit.
If we send a SIGQUIT, which is done through
"Ctrl+\", here, we can see that since the program doesn't have a way of dealing with SIGQUIT,
it does the default operation, which is
terminate the program.
And you could use this, for example,
if someone Ctrl+C's your program, and your program is supposed to do something,
like you maybe want to save the intermediate state of your program
to a file, so you can recover it for later.
This is how you could write a handler like this.
Can you repeat the question?
What did you type right now, when it stopped?
So I...
So what I typed is, I type "Ctrl+C" to try to stop it
but it didn't, because SIGINT is captured by the program. Then I type
"Ctrl+\", which sends a SIGQUIT, which is a different signal,
and this signal is not captured by the program.
It's also worth mentioning that there is a couple of
signals that cannot be captured by software. There is a couple of signals
like SIGKILL
that cannot be captured. Like that, it will
terminate the execution of the process, no matter what.
And it can be sometimes harmful. You do not want to be using it by
default, because this can leave for example an orphan child, orphaned children processes.
Like if a process has other small children processes that it started, and you
SIGKILL it, all of those will keep running in there,
but they won't have a parent, and you can maybe have a really weird behavior going on.
What signal is given to the program if we log off?
If you log off?
That would be... so for example, if you're in an SSH connection and you close the connection,
that is the hang-up signal,
SIGHUP, which I'm gonna cover in an example. So this is what would be sent up.
And you could write for example, if you want the process to keep working even if you close
that, you can write a wrapper around that to ignore that signal.
Let's display what we could do with the stop and continue.
So, for example, we can start a really long process. Let's sleep a thousand, we're gonna take forever.
We can control-c,
"Ctrl+Z", sorry,
and if we do "Ctrl+Z" we can see that the terminal is saying "it's suspended".
What this actually meant is that this process was sent a SIGSTOP signal and now is
still there, you could continue its execution, but right now it's completely stopped and in the background
and we can launch a different program.
When we try to run this program,
please notice that I have included an "&" at the end.
This tells bash that I want this program to start running in the background.
This is kind of related to all these
concepts of running programs in the shell, but backgrounded.
And what is gonna happen is the program is gonna start
but it's not gonna take over my prompt.
If I just ran this command without this, I could not do anything.
I would have no access to the prompt until the command either finished
or I ended it abruptly. But if I do this,
it's saying "there's a new process which is this".
This is the process identifying number,
we can ignore this for now.
If I type the command "jobs", I get the output that I have a suspended job
that is the "sleep 1000" job.
And then I have another running job,
which is this "NOHUP sleep 2000".
Say I want to continue the first job.
The first job is suspended, it's not executing anymore.
I can continue that doing "BG %1"
That "%" is referring to the fact that I want to refer to this specific
process. And now, if I do that and I look at the jobs,
now this job is running again. Now
both of them are running.
If I wanted to stop these all, I can use the kill command.
The kill command
is for killing jobs,
which is just stopping them, intuitively,
but actually it's really useful.
The kill command just allows you to send any sort of Unix signal.
So here for example, instead of killing it completely,
we just send a stop signal.
Here I'm gonna send a stop signal, which is gonna pause the process again.
I still have to include the identifier,
because without the identifier the shell wouldn't know whether to stop the first one or the second one.
Now it's said this has been suspended, because there was a signal sent.
If I do "jobs", again, we can see that the second one is running
and the first one has been stopped.
Going back to one of the questions,
what happens when you close the cell, for example,
and why sometimes people will say that you should use this NOHUP command
before your run jobs in a remote session.
This is because if we try to send a hung up command to the first job
it's gonna, in a similar fashion as the other signals,
it's gonna hang it up and that's gonna terminate the job.
And the first job isn't there anymore
whereas we have still the second job running.
However, if we try to send the signal to the second job
what will happen if we close our terminal right now
is it's still running.
Like NOHUP, what it's doing is kind of encapsulating
whatever command you're executing and
ignoring wherever you get a hang up signal,
and just ignoring that so it can keep running.
And if we send the "kill" signal to the second job,
that one can't be ignored and that will kill the job, no matter what.
And we don't have any jobs anymore.
That kind of completes the section on job control.
Any questions so far? Anything that wasn't fully clear?
What does BG do?
So BG...
There are like two commands. Whenever you have a command that has been backgrounded
and is stopped you can use BG (short for background)
to continue that process running on the background.
That's equivalent of just kind of sending it
a continue signal, so it keeps running.
And then there's another one which is called FG, if you want to
recover it to the foreground and you want to reattach your standard output.
Okay, good.
Jobs are useful and in general, I think knowing about signals can be
really beneficial when dealing with some part of Unix
but most of the time what you actually want to do is something along the lines of
having your editor in one side and then the program in another, and maybe
monitoring what the resource consumption is in our tab.
We could achieve this using probably what you have seen a lot of the time,
which is just opening more windows.
We can keep opening terminal windows.
But the fact is there are kind of more convenient solutions to this and
this is what a terminal multiplexer does.
A terminal multiplexer like tmux
will let you create different workspaces that you can work in,
and quickly kind of,
this has a huge variety of functionality,
It will let you rearrange the environment and it will let you have different sessions.
There's another more...
older command, which is called "screen",
that might be more readily available.
But I think the concept kind of extrapolates to both.
We recommend tmux, that you go and learn it.
And in fact, we have exercises on it.
I'm gonna showcase a different scenario right now.
So whenever I talked...
Oh, let me make a quick note.
There are kind of three core concepts in tmux, that I'm gonna go through and
the main idea is that there are what is called
"sessions".
Sessions have "windows" and
windows have "panes".
It's gonna be kind of useful to keep this hierarchy in mind.
You can pretty much equate "windows" to what "tabs" are in other editors and others,
like for example your web browser.
I'm gonna go through the features, mainly what you can do at the different levels.
So first, when we do tmux, that starts a session.
And here right now it seems like nothing changed
but what's happening right now is we're within a shell that is different from the one we started before.
So in our shell we started a process, that is tmux
and that tmux started a different process, which is the shell we're currently in.
And the nice thing about this is that
that tmux process is separate from the original shell process.
So
here, we can do things.
We can do "ls -la", for example, to tell us what is going on in here.
And then we can start running our program, and it will start running in there
and we can do "Ctrl+A d", for example, to detach
to detach from the session.
And if we do "tmux a"
that's gonna reattach us to the session.
So the process,
we abandon the process counting numbers.
This really silly Python program that was just counting numbers,
we left it running there.
And if we tmux...
Hey, the process is still running there.
And we could close this entire terminal and open a new one and
we could still reattach because this tmux session is still running.
Again, we can...
Before I go any further.
Pretty much... Unlike Vim, where you have this notion of modes,
tmux will work in a more emacsy way, which is
every command, pretty much every command in tmux,
you could enter it through the...
it has a command line, that we could use.
But I recommend you to get familiar with the key bindings.
It can be somehow non intuitive at first,
but once you get used to them...
"Ctrl+C", yeah
When you get familiar with them, you will be much faster just using the key bindings than using the commands.
One note about the key bindings: all the key bindings have a form that is like
you type a prefix and then some key.
So for example, to detach we do "Ctrl+A" and then "D".
This means you press "Ctrl+A" first, you release that, and then press "D" to detach.
On default tmux, the prefix is "Ctrl+B",
but you will find that most people will have this remapped to "Ctrl+A"
because it's a much more ergonomic type on the keyboard.
You can find more about how to do these things in one of the exercises,
where we link you to the basics and how to do some kind of quality of life modifications to tmux.
Going back to the concept of sessions,
we can create a new session just doing something like tmux new
and we can give sessions names.
So we can do like "tmux new -t foobar"
and this is a completely different session, that we have started.
We can work here, we can detach from it.
"tmux ls" will tell us that we have two different sessions:
the first one is named "0", because I didn't give it a name,
and the second one is called "foobar".
I can attach the foobar session
and I can end it.
And it's really nice because
having this you can kind of work in completely different projects.
For example, having two different tmux sessions and different
editor sessions, different processes running...
When you are within a session, we start with the concept of windows.
Here we have a single window, but we can use "Ctrl+A c" (for "create")
to open a new window.
And here nothing is executing.
What it's doing is, tmux has opened a new shell for us
and we can start running another one of these programs here.
And to quickly jump between the tabs, we can do "Ctrl+A" and "previous",
"p" for "previous",
and that will go up to the previous window.
"Ctrl+A" "next", to go to the next window.
You can also use the numbers. So if we start opening a lot of these tabs,
we could use "Ctrl+A 1", to specifically jump to the
to the window that is number "1".
And, lastly, it's also pretty useful to know sometimes
that you can rename them.
For example here I'm executing this Python process,
but that might not be really informative and I want...
I maybe want to have something like execution or something like that and
that will rename the name of that window so you can have this really neatly organized.
This still doesn't solve the need when you want to have two things at the same time in your terminal,
like in the same display.
This is what panes are for. Right now, here
we have a window with a single pane
(all the windows that we have opened so far have a single pane).
But if we do 'Ctrl+A "'
this will split the current display into two different panes.
So, you see, the one we open below is a different shell from the one we have above,
and we can run any process that we want here.
We can keep splitting this, if we do "Ctrl+A %"
that will split vertically. And you can kind of
rearrange these tabs using a lot of different commands.
One that I find very useful, when you are starting and it's kind of frustrating,
rearranging them.
Before I explain that, to move through these panes, which is
something you want to be doing all the time
You just do "Ctrl+A" and the arrow keys, and that will let you quickly
navigate through the different windows, and execute again...
I'm doing a lot of "ls -a"
I can do "HTOP", that we'll explain in the debugging and profiling lecture.
And we can just navigate through them, again
like to rearrange there's another slew of commands,
you will go through some in the Exercises
"Ctrl+A" space is pretty neat, because it will kind of equispace the current ones
and let you through different layouts.
Some of them are too small for my current
terminal config, but that covers, I think, most of it.
Oh, there's also,
here, for example, this Vim execution that we have started,
is too small for what the current tmux pane is.
So one of the things that really is much more convenient to do in tmux,
in contrast to having multiple terminal windows, is that
you can zoom into this, you can ask by doing "Ctrl+A z", for "zoom".
It will expand the pane to take over all the space,
and then "Ctrl+A z", again will go back to it.
Any questions for terminal multiplexers, or like, tmux concretely?
Is it running all the same thing?
Like, is there any difference in execution between running it in different windows?
Is it really just doing it all the same, so that you can see it?
Yeah, it wouldn't be any different from having two terminal windows open in your computer.
Like both of them are gonna be running. Of course, when it gets to the CPU,
this is gonna be multiplexed again.
Like there's like a timesharing mechanism going there
but there's no difference.
tmux is just making this much more convenient to use by giving you this visual layout
that you can quickly manipulate through.
And one of the main advantages will come when we reach the remote machines
because you can leave one of these, we can detach from one of these tmux systems,
close the connection and even if we close the connection and
and the terminal is gonna send a hang-up signal,
that's not gonna close all the tmux's that have been started.
Any other questions?
Let me disable the key-caster.
So now we're gonna move into the topic of dotfiles and, in general,
how to kind of configure your shell to do the things you want to do
and mainly how to do them quicker and in a more convenient way.
I'm gonna motivate this using aliases first.
So what an alias is,
is that by now, you might be starting to do something like
a lot of the time, I just want to LS a directory and I want to display all the contents into a list format
and in a human readable thing.
And it's fine. Like it's not that long of a command.
But as you start building longer and longer commands,
it can become kind of bothersome having to retype them again and again.
This is one of the reasons why aliases are useful.
Alias is a command that will be a built-in in your shell,
and what it will do is
it will remap a short sequence of characters to a longer sequence.
So if I do, for example, here
alias ll="ls -lah"
If I execute this command, this is gonna call the "alias" command with this argument
and the LS is going to update
the environment in my shell to be aware of this mapping.
So if I now do LL,
it's executing that command without me having to type the entire command.
It can be really handy for many, many reasons.
One thing to note before I go any further is that
here, alias is not anything special compared to other commands,
it's just taking a single argument.
And there is no space around this equals and that's
because alias takes a single argument
and if you try doing
something like this, that's giving it more than one argument
and that's not gonna work because that's not the format it expects.
So other use cases that work for aliases,
as I was saying,
for some things it may be much more convenient,
like
one of my favorites is git status.
It's extremely long, and I don't like typing that long of a command every so often,
because you end up taking a lot of time.
So GS will replace for doing the git status
You can also use them to alias things that you mistype often,
so you can do "sl=ls",
that will work.
Other useful mappings are,
you might want to alias a command to itself
but with a default flag.
So here what is going on is I'm creating an alias
which is an alias for the move command,
which is MV and I'm aliasing it to the same command but adding the "-i" flag.
And this "-i" flag, if you go through the man page and look at it, it stands for "interactive".
And what it will do is it will prompt me before I do an overwrite.
So once I have executed this, I can do something like
I want to move "aliases" into "case".
By default "move" won't ask, and if "case" already exists, it will be over.
That's fine, I'm going to overwrite whatever that's there.
But here it's now expanded,
"move" has been expanded into this "move -i"
and it's using that to ask me
"Oh, are you sure you want to overwrite this?"
And I can say no, I don't want to lose that file.
Lastly, you can use "alias move"
to ask for what this alias stands for.
So it will tell you so you can quickly make sure
what the command that you are executing actually is.
One inconvenient part about, for example, having aliases is how will you go about
persisting them into your current environment?
Like, if I were to close this terminal now,
all these aliases will go away.
And you don't want to be kind of retyping these commands
and more generally, if you start configuring your shell more and more,
you want some way of bootstrapping all this configuration.
You will find that most shell command programs
will use some sort of text based configuration file.
And this is what we usually call "dotfiles", because they start with a dot for historical reasons.
So for bash in our case, which is a shell,
we can look at the bashrc.
For demonstration purposes, here I have been using ZSH,
which is a different shell, and I'm going to be configuring bash, and starting bash.
So if I create an entry here and I say
SL maps to LS
And I have modified that, and now I start bash.
Bash is kind of completely unconfigured, but now if I do SL...
Hm, that's unexpected.
Oh, good. Good getting that.
So it matters where you config file is,
your config file needs to be in your home folder.
So your configuration file for bash will live in that "~",
which will expand to your home directory,
and then bashrc.
And here we can create the alias
and now we start a bash session and we do SL.
Now it has been loaded, and this is loaded at the beginning when this
bash program is started.
All this configuration is loaded and you can, not only use aliases, they can have a lot of parts of configuration.
So for example here, I have a prompt which is fairly useless.
It has just given me the name of the shell, which is bash,
and the version, which is 5.0. I don't want this to be displayed and
as with many things in your shell, this is just an environment variable.
So the "PS1" is just the prompt string
for your prompt and
we can actually modify this to just be a "> " symbol.
and now that has been modified, and we have that. But if we exit and call bash again,
that was lost. However, if we add this entry and say, oh we want "PS1"
to be
this and
we call bash again, this has been persisted. And we can keep modifying this configuration.
So maybe we want to include
where the
working directory that we are is in, and
that's telling us the same information that we had in the other shell.
And there are many, many options,
shells are highly, highly configurable, and
it's not only cells that are configured through these files,
there are many other programs. As we saw for example in the editors lecture, Vim is also
configured this way. We gave you this vimrc file and told you to put it under your
home/.vimrc
and this is the same concept, but just for Vim. It's just giving it a set of
instructions that it should load when it's started, so you can keep a configuration that you want.
And even non...
kind of a lot of programs will support this. For instance, my terminal emulator, which is another concept,
which is the program that is
running the shell, in a way, and displaying this into the screen in my computer.
It can also be configured this way, so
if I modify this I can
change the size of the font. Like right now, for example, I have increased the font size a lot
for demonstration purposes, but
if I change this entry and make it for example
28 and write this value, you see that the size of the font has changed,
because I edited this text file that specifies how my terminal emulator should work.
Any questions so far?
With dotfiles.
Okay, it can be a bit daunting knowing that there is like this endless wall of configurations,
and how do you go about learning about what can be configured?
The good news is that
we have linked you to really good resources in the lecture notes.
But the main idea is that a lot of people really like just configuring these tools and have uploaded
their configuration files to GitHub, another different kind of repositories online.
So for example, here we are on GitHub,
we search for dotfiles, and can see that there are like
thousands of repositories of people sharing their configuration files. We have also...
Like, the class instructors have linked our dotfiles.
So if you really want to know how any part of our setup is working
you can go through it and try to figure it out.
You can also feel free to ask us.
If we go for example to this repository here
we can see that there's many, many files that you can configure.
For example, there is one for bash, the first couple of ones are for git, that will be probably be covered in the
version control lecture tomorrow.
If we go for example to the bash profile, which is a different form of what we saw in the bashrc,
it can be really useful because you can learn through
just looking at the manual page, but the manual pages is, a lot of the time
just kind of like a descriptive explanation of all the different options
and sometimes it's more helpful
going through examples of what people have done and trying to understand why they did it
and how it's helping their workflow.
We can say here that this person has done case-insensitive globbing.
We covered globbing as this kind of filename expansion
trick in the shell scripting and tools.
And here you say no, I don't want this to matter,
whether using uppercase and lowercase,
and just setting this option in the shell for these things to work this way
Similarly, there is for example aliases.
Here you can see a lot of aliases that this person is doing. For example, "d" for
"d" for "Dropbox", sorry, because that's just much shorter.
"g" for "git"...
Say we go, for example, with vimrc. It can be actually very, very informative,
going through this and trying to extract useful information.
We do not recommend just kind of getting one huge blob of this and copying this into your config files,
because maybe things are prettier, but you might not really understand what is going on.
Lastly one thing I want to mention about dotfiles is that
people not only try to push these
files into GitHub just so other people can read it, that's
one reason. They also make really sure they can
reproduce their setup. And to do that they use a slew of different tools.
Oops, went a little too far.
So GNU Stow is, for example, one of them
and the trick that they are doing is
they are kind of putting all their dotfiles in a folder and they are
faking to the system, using a tool called symlinks,
that they are actually what they're not. I'm gonna
draw really quick what I mean by that.
So a common folder structure might look like you have your home folder and
in this home folder you might have your
bashrc, that contains your bash configuration, you might have your vimrc and
it would be really great if you could keep this under version control.
But the thing is, you might not want to have a git repository,
which will be covered tomorrow,
in your home folder.
So what people usually do is they create a dotfiles repository,
and then they have entries here for their
bashrc and their vimrc. And this is where actually
the files are
and what they are doing is they're just
telling the OS to forward, whenever anyone
wants to read this file or write to this file, just forward this to this other file.
This is a concept called symlinks
and it's useful in this scenario,
but it in general it's a really useful tool in UNIX
that we haven't covered so far in the lectures
but you might be...
that you should be familiar with.
And in general, the syntax will be "ln -s"
for specifying a symbolic link and then you will put the path to the file
that you want to create and then the
symlink that you want to create.
And
All these all these kind of fancy tools that we're seeing here listed,
they all amount to doing some sort of this trick, so that you can have all your dotfiles neat and tidy
into a folder, and then they can be version-controlled, and they can be
symlinked so the rest of the programs can find them in their default locations.
Any questions regarding dotfiles?
Do you need to have the dotfiles in your home folder, and then also dotfiles in the version control folder?
So what you will have is, pretty much every program,
for example bash,
will always look for "home/.bashrc".
That's where the program is going to look for.
What you do when you do a symlink is, you place your "home/.bashrc"
it's just a file that is kind of a special file in UNIX,
that says oh, whenever you want to read this file go to this other file.
There's no content, like there is no...
your aliases are not part of this dotfile. That file is just kind of like a pointer, saying now you should
go that other way.
And by doing that you can have your other file
in that other folder.
If version controlling is not useful, think about
what if you want to have them in your Dropbox folder, so they're synced to the cloud,
for example. That's kind of another use case where like symlinks could be really useful
So you don't need the folder dotfiles to be in the home directory, right?
Because you can just use the symlink, that points somewhere else.
As long as you have a way for the default path to resolve wherever you have it, yeah.
Last thing I want to cover in the lecture...
Oh, sorry, any other questions about dotfiles?
Last thing I want to cover in the lecture is working with remote machines,
which is a thing that you will run into,
sooner or later.
And there are a few things that will make your life much easier when dealing with remote machines
if you know about them.
Right now maybe because you are using the Athena cluster,
but later on, during your programming career,
it's pretty sure that
there is a fairly ubiquitous concept of having your
local working environment and then having some production server that is actually running the
code, so it is really good to get familiar
about how to work in/with remote machines.
So the main command for working with remote machines is SSH.
SSH is just like a secure shell, it's just gonna take the responsibility for
reaching wherever we want or tell it to go
and trying to open a session there.
So here the syntax is:
"JJGO" is the user that I want to use in the remote machine,
and this is because the user is
different from the one I have my local machine, which will be the case a lot of the time,
then the "@" is telling the terminal that this separates
what the user is from what the address is.
And here I'm using an IP address because what I'm actually doing is
I have a virtual machine in my computer,
that is the one that is remote right now.
And I'm gonna be SSH'ing into it. This is the
URL that I'm using,
sorry, the IP that I'm using,
but you might also see things like
oh I want to SSH as "JJGO"
at "foobar.mit.edu"
That's probably something more common, if you are using some
remote server that has a DNS name.
So going back to a regular command,
we try to SSH, it asks us for a password,
really common thing.
And now we're there. We have...
we're still in our same terminal emulator
but right now SSH is kind of forwarding the entire virtual display to display what the
remote shell is displaying. And we can execute commands here and
we'll see the remote files
A couple of handy things to know about SSH, that were briefly covered in the
data wrangling lecture, is that SSH is not only good for just
opening connections. It will also let you just execute commands remotely.
So for example, if I do that, it's gonna ask me
what is my password?, again.
And it's executing this command
then coming back to my terminal
and piping the output of what that command was, in the remote machine,
through the standard output in my current cell.
And I could have this in...
I could have this in a pipe, and
this will work and we'll just
drop all this output and then have a local pipe
where I can keep working.
So far, it has been kind of inconvenient, having to type our password.
There's one really good trick for this.
It's we can use something called "SSH keys".
SSH keys just use public key encryption
to create a pair of SSH keys, a public key and a private key, and then
you can give the server the public part of the key.
So you copy the public key and then whenever you try to
authenticate instead of using your password, it's gonna use the private key to
prove to the server that you are actually who you say you are.
We can quickly showcase how you will go
about doing this.
Right now I don't have any SSH keys, so I'm gonna create a couple of them.
First thing, it's just gonna ask me where I want this key to live.
Unsurprisingly, it's doing this.
This is my home folder and then it's using this ".ssh" path,
which refers back to the same concept that we covered earlier about having
dotfiles. Like ".ssh" is a folder that contains a lot of the
configuration files for how you want SSH to behave.
So it will ask us a passphrase.
The passphrase is to encrypt the private part of the key
because if someone gets your private key, if you don't have a password protected
private key, if they get that key
they can use that key to impersonate you in any server.
Whereas if you add a passphrase,
they will have to know what the passphrase is to actually use the key.
It has created a keeper. We can check that these two files are now under ssh.
And we can see...
We have these two files: we have the 25519 and the public key.
And if we "cat" through the output,
that key is actually not like any fancy binary file, it's
just a text file that has the contents of the public key and some
alias name for it, so we can know what this public key is.
The way we can tell the server that we're authorized to SSH there
is by just actually copying this file, like copying this string into a file,
that is ".ssh/authorized_keys".
So here what I'm doing is I'm
catting the output of this file
which is just this line of text that we want to copy
and I'm piping that into SSH and then remotely
I'm asking "tee" to dump the contents of the standard input
into ".ssh/authorized_keys".
And if we do that, obviously it's gonna ask us for a password.
It was copied, and now we can check that if we try
to SSH again,
It's going to first ask us for a passphrase
but you can arrange that so that it's saved in the session
and we didn't actually have to type the key for the server.
And I can kind of show that again.
More things that are useful.
Oh, we can do...
If that command seemed a little bit janky,
you can actually use this command that is built for this,
so you don't have to kind of craft this "ssh tee" command.
That is just called "ssh-copy-id".
And we can do the same
and it's gonna copy the key.
And now, if we try to SSH,
we can SSH without actually typing any key at all,
or any password.
More things.
We will probably want to copy files.
You cannot use "CP"
but you can use "SCP", for "SSH copy".
And here we can specify that we want to copy this local file called notes
and the syntax is kind of similar.
We want to copy to this remote and
then we have a semicolon to separate what the path is going to be.
And then we have
oh, we want to copy this as notes
but we could also copy this as foobar.
And if we do that, it has been executed
and it's telling us that all the contents have been copied there.
If you're gonna be copying a lot of files,
there is a better command that you should be using
that is called "RSYNC". For example, here
just by specifying these three flags,
I'm telling RSYNC to kind of preserve all the permissions whenever possible
to try to check if the file has already been copied.
For example, SCP will try to copy files that are already there.
This will happen for example if you are trying to copy
and the connection interrupts in the middle of it.
SCP will start from the very beginning, trying to copy every file,
whereas RSYNC will continue from where it stopped.
And here,
we ask it to copy the entire folder and
it's just really quickly copied the entire folder.
One of the other things to know about SSH is that
the equivalent of the dot file for SSH is the "SSH config".
So if we edit the SSH config to be
If I edit the SSH config to look something like this,
instead of having to, every time, type "ssh jjgo",
having this really long string so I can like refer to this specific remote,
I want to refer, with the specific user name,
I can have something here that says
this is the username, this is the host name, that this
host is referring to and you should use this identity file.
And if I copy this,
this is right now in my local folder,
I can copy this into ssh.
Now, instead of having to do this really long command, I can just say
I just want to SSH into the host called VM.
And by doing that, it's grabbing all that configuration from the SSH config
and applying it here.
This solution is much better than something like creating an alias for SSH,
because other programs like SCP and RSYNC
also know about the dotfiles for SSH and will use them whenever they are there.
Last thing I want to cover about remote machines is that here, for example, we'll have tmux and we can,
like I was saying before, we can start editing some file
and we can start running some job.
For example, something like HTOP.
And this is running here, we can
detach from it,
close the connection and
then SSH back. And then, if you do "tmux a",
everything is as you left it, like nothing has really changed.
And if you have things executing there in the background, they will keep executing.
I think that, pretty much, ends all I have to say for this tool.
Any questions related to remote machines?
That's a really good question. So what I do for that,
Oh, yes, sorry.
So the question is, how do you deal with trying to use tmux in your local machine,
and also trying to use tmux in the remote machine?
There are a couple of tricks for dealing with that.
The first one is changing the prefix.
So what I do, for example, is
in my local machine the prefix I have changed from "Ctrl+B" to "Ctrl+A" and
then in remove machines this is still "Ctrl+B".
So I can kind of swap between,
if I want to do things to the local tmux I will do "Ctrl+A"
and if I want to do things to the remote tmux I would do "Ctrl+B".
Another thing is that you can have separate configs,
so I can do something like this, and then...
Ah, because I don't have my own ssh config, yeah.
But if you...
Um, I can SSH "VM".
Here, what you see,
the difference between these two bars, for example,
is because the tmux config is different.
As you will see in the exercises, the tmux configuration is in
the tmux.conf
And in tmux.conf,
here you can do a lot of things like changing the color depending on the host you are
so you can get like quick visual feedback about where you are, or
if you have a nested session. Also, tmux will,
if you're in the same host and you try to tmux within a tmux session,
it will kind of prevent you from doing it so you don't run into issues.
Any other questions related, to kind of all the topics we have covered.
Another answer to that question is also, if you type the prefix twice,
it sends it once to the underlying shell.
So the local binding is "Ctrl+A" and the remote binding is "Ctrl+A",
You could type "Ctrl+A", "Ctrl+A" and then "D", for example, detaches from the remote, basically.
I think that ends the class for today, there's a bunch of exercises related to all these main topics and
we're gonna be holding office hours today, too. So feel free to come and ask us any questions.