This shows you the differences between two versions of the page.
ii:labs:01:tasks:02 [2021/10/09 00:50] radu.mantu [02. [40p] tmux] |
ii:labs:01:tasks:02 [2024/10/18 12:14] (current) radu.mantu |
||
---|---|---|---|
Line 3: | Line 3: | ||
**tmux** is a terminal multiplexer. It allows you to split a terminal into multiple views on the same screen, create multiple sessions, etc. | **tmux** is a terminal multiplexer. It allows you to split a terminal into multiple views on the same screen, create multiple sessions, etc. | ||
- | {{ :ii:labs:01:tasks:tmux-demo.gif?700 |}} | + | [[https://ocw.cs.pub.ro/courses/_media/ii/labs/01/tasks/tmux-demo.gif|{{ :ii:labs:01:tasks:tmux-demo.gif?700 |}}]] |
+ | <html><center><i> Click GIF to maximize. </i></center></html> | ||
One particularly interesting feature is that you can detach yourself from a session only to reattach later. Take the following scenario: you need to start a process on a remote machine once you **ssh** into it. The process needs to keep running even after you exit. How do you launch that process? | One particularly interesting feature is that you can detach yourself from a session only to reattach later. Take the following scenario: you need to start a process on a remote machine once you **ssh** into it. The process needs to keep running even after you exit. How do you launch that process? | ||
Line 15: | Line 16: | ||
* ''<INPUT_FILE'': when the terminal dies, your //stdin//, //stdout// and //stderr// are gone as well. Even if the children survive their parent's death, reading or writing to any of these three "files" will cause an error. In other words they still die, just less gracefully. If you know that your process never reads from //stdin//, you can skip this. Otherwise, it's a good idea to redirect the input from a file that you know will persist, such as a storage-backed file. | * ''<INPUT_FILE'': when the terminal dies, your //stdin//, //stdout// and //stderr// are gone as well. Even if the children survive their parent's death, reading or writing to any of these three "files" will cause an error. In other words they still die, just less gracefully. If you know that your process never reads from //stdin//, you can skip this. Otherwise, it's a good idea to redirect the input from a file that you know will persist, such as a storage-backed file. | ||
* ''&>OUTPUT_FILE'': the explanation above applies here as well. ''&'' is just a shorthand for both //stdout// and //stderr//. So you redirect both to the same file. Note that this file (or that which replaces stdin, for that matter) can be// /dev/null// or// /dev/zero. // | * ''&>OUTPUT_FILE'': the explanation above applies here as well. ''&'' is just a shorthand for both //stdout// and //stderr//. So you redirect both to the same file. Note that this file (or that which replaces stdin, for that matter) can be// /dev/null// or// /dev/zero. // | ||
- | * ''&'': this final component of our command tells our shell to start the process in background, not needing to put the parent (i.e.: **zsh** or **bash**) on-hold until it finishes. | + | * ''&'': this final component of our command tells our shell to start the process in background, not needing to pester the parent (i.e.: **zsh** or **bash**), putting it on-hold until it finishes. |
- | Pretty complicated, right? And even if you do this, when you start a new SSH session it will be //very// difficult to change these parameters (e.g.: redirecting //stdout// to your terminal). I bet **tmux** looks pretty good right about now :) | + | Pretty complicated, right? And even if you do this, when you start a new SSH session it will be //very// difficult to change these parameters (e.g.: redirecting //stdout// to your terminal) while the process is running. I bet **tmux** looks pretty good right about now :) |
=== [10p] Task A - Installation === | === [10p] Task A - Installation === | ||
- | This is a lot less painful than it was for **zsh**, so don't worry. So let's install **tmux** and run it: | + | This is a lot less painful than it was for **zsh**, so don't worry. Let's install **tmux** and run it: |
<code> | <code> | ||
Line 35: | Line 36: | ||
* //<Ctrl + B> "// : split terminal vertically | * //<Ctrl + B> "// : split terminal vertically | ||
* //<Ctrl + B> ←↑↓→// : cycle through active terminals | * //<Ctrl + B> ←↑↓→// : cycle through active terminals | ||
+ | * //<Ctrl + B + ←↑↓→>// : resize active terminals | ||
Note that you can rebind all these shortcuts in a config file. For now, let's add a rather useful option: allowing to switch active shell by clicking on it. Also, the color of the **zsh** auto-completion plugin might have defaulted to white; let's fix this as well. | Note that you can rebind all these shortcuts in a config file. For now, let's add a rather useful option: allowing to switch active shell by clicking on it. Also, the color of the **zsh** auto-completion plugin might have defaulted to white; let's fix this as well. | ||
Line 43: | Line 45: | ||
$ tmux source-file ~/.tmux.conf | $ tmux source-file ~/.tmux.conf | ||
</code> | </code> | ||
+ | </note> | ||
+ | |||
+ | <note important> | ||
+ | If you are working in a Virtual Machine, it may be unable to capture key combinations such as //<Ctrl + B>//. There are two alternatives to using these shortcuts. | ||
+ | - right click on the terminal (while running tmux) and drag the mouse. A menu should appear with some basic commands. Drag the cursor over the command and release the mouse button | ||
+ | - run ''tmux split-window''. This command shows all configured binds. We notice the ''split-window [-h]'' command being used, so try running ''tmux split-window'' with a **tmux** instance already running. This will send it a split screen request, just like //<Ctrl + B> "//. | ||
</note> | </note> | ||
Line 60: | Line 68: | ||
=== [10p] Task C - Start tmux by default === | === [10p] Task C - Start tmux by default === | ||
- | If you open a new terminal with //<Ctrl + Alt + T>// you will notice that **tmux** is not running. When **zsh** starts up, it automatically sources //.zshrc//, so lets make it execute **tmux** by adding the following at the end: | + | If you open a new terminal with //<Ctrl + Alt + T>// you will notice that **tmux** is not running. When **zsh** starts up, it automatically sources //.zshrc//, so let's make it execute **tmux** by adding the following at the end: |
<code> | <code> | ||
# start tmux session (only once!) | # start tmux session (only once!) | ||
- | if [ -z "$TMUX" ] && [[ "$USER" == "<YOUR_USERNAME_GOES_HERE>" ]]; then | + | if [ -z "$TMUX" ] && [[ "$USER" == "YOUR_USERNAME_GOES_HERE" ]]; then |
exec tmux | exec tmux | ||
fi | fi | ||
Line 71: | Line 79: | ||
This may require some explanations. If at any point you're feeling lost, check out the diagram in the spoiler below (or ask). | This may require some explanations. If at any point you're feeling lost, check out the diagram in the spoiler below (or ask). | ||
* ''[ -z "$TMUX" ]'': Your shell defines some //environment variables// which can be seen by running the ''env'' command. Unless you have an active **tmux** session, there is no //TMUX// variable. So if that variable is empty (which in **bash** / **zsh** means it doesn't exist), we need to start **tmux**. But remember! **tmux** then starts your default shell (i.e.: **zsh**), which sources //.zshrc// again, and executes **tmux**... again... See where I'm going with this? You run into an infinite loop of starting **tmux** and **zsh** and your terminal will simply crash. So we need to start **tmux** __exactly__ once. | * ''[ -z "$TMUX" ]'': Your shell defines some //environment variables// which can be seen by running the ''env'' command. Unless you have an active **tmux** session, there is no //TMUX// variable. So if that variable is empty (which in **bash** / **zsh** means it doesn't exist), we need to start **tmux**. But remember! **tmux** then starts your default shell (i.e.: **zsh**), which sources //.zshrc// again, and executes **tmux**... again... See where I'm going with this? You run into an infinite loop of starting **tmux** and **zsh** and your terminal will simply crash. So we need to start **tmux** __exactly__ once. | ||
- | * ''%%[[%% "$USER" == "..." %%]]%%'': This is a solution for a rather dumb problem. Up until now, you've set up **zsh** only for your user but not for //root//. If you create// /root/.zshrc// and in it you just source the main //.zshrc// in your home, you will end up executing **tmux** again, but only once more. The reason is that the //TMUX// environment variable is not passed to the new user's shell. Why this is annoying is that the second **tmux** instance will add another status bar to the bottom of your screen. Normally, when you start a terminal with //<Ctrl + Alt + T>// you don't run a shell a root, so this workaround is somewhat valid. | + | * ''%%[[%% "$USER" == "..." %%]]%%'': This is a solution for a rather dumb problem. Up until now, you've set up **zsh** only for your user but not for //root//. If you create// /root/.zshrc// and in it you just source the main //.zshrc// in your home, you will end up executing **tmux** again, but only once more. The reason is that the //TMUX// environment variable is not passed to the new user's shell. Why this is annoying is that the second **tmux** instance will add another status bar to the bottom of your screen. Normally, when you start a terminal with //<Ctrl + Alt + T>// you don't run a shell as //root//, so this workaround is somewhat valid. |
* ''exec tmux'': By running ''tmux'' you will be able to ''exit'' or //<Ctrl + D>// and you'll return to the original **zsh** shell. By running ''exec tmux'' you will effectively //replace// your current shell, so when you exit, you will close the entire terminal window. | * ''exec tmux'': By running ''tmux'' you will be able to ''exit'' or //<Ctrl + D>// and you'll return to the original **zsh** shell. By running ''exec tmux'' you will effectively //replace// your current shell, so when you exit, you will close the entire terminal window. | ||
<spoiler> | <spoiler> | ||
- | {{ :ii:labs:01:tasks:tmux-zsh-flow.png?400 |}} | + | [[https://ocw.cs.pub.ro/courses/_media/ii/labs/01/tasks/tmux-zsh-flow.png|{{ :ii:labs:01:tasks:tmux-zsh-flow.png?500 |}}]] |
</spoiler> | </spoiler> | ||