diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/blog/2023-02-25-job-control/job-control.md | 145 | ||||
| -rw-r--r-- | src/blog/2023-02-25-job-control/jobs-diagram.pdf | bin | 0 -> 27720 bytes | |||
| -rw-r--r-- | src/blog/2023-02-25-job-control/jobs-diagram.png | bin | 0 -> 56672 bytes | |||
| -rw-r--r-- | src/blog/2023-02-25-job-control/jobs-diagram.tex | 38 | ||||
| -rw-r--r-- | src/blog/blog.md | 1 | ||||
| -rw-r--r-- | src/blog/feed.xml | 7 |
6 files changed, 191 insertions, 0 deletions
diff --git a/src/blog/2023-02-25-job-control/job-control.md b/src/blog/2023-02-25-job-control/job-control.md new file mode 100644 index 0000000..8fdb60b --- /dev/null +++ b/src/blog/2023-02-25-job-control/job-control.md | |||
| @@ -0,0 +1,145 @@ | |||
| 1 | # Job control: one shell is all you need | ||
| 2 | |||
| 3 | If you work in a graphical desktop environment, you are most likely | ||
| 4 | used to multi-tasking. You can listen to music while you type your | ||
| 5 | blog posts, browse the web while your code compiles, and so on. | ||
| 6 | |||
| 7 | But what if you are interacting with your machine via a command | ||
| 8 | line? Sure, you can use a | ||
| 9 | [terminal multiplexer](https://en.wikipedia.org/wiki/Terminal_multiplexer) | ||
| 10 | like [tmux](https://tmux.github.io). | ||
| 11 | But what if you forgot to run it before starting your tasks? And now | ||
| 12 | you are updating your packages and the shell is locked?! What a nightmare! | ||
| 13 | |||
| 14 | Luckily, the UNIX shell has a job control system that allows you | ||
| 15 | to run multiple tasks at the same time. What I explain in this post | ||
| 16 | has been tested on ksh on OpenBSD, but should work in the same way | ||
| 17 | on Linux or any UNIX-like OS with a POSIX-compatible shell - except | ||
| 18 | perhaps for the key combinations to suspend or kill a job. | ||
| 19 | |||
| 20 | This post is not meant to be an introduction to what the shell is, | ||
| 21 | but it is worth spending a few words to clear up some common (and | ||
| 22 | understandable) confusion. I'll keep them really *a few*. | ||
| 23 | |||
| 24 | ## The terminal vs the shell, in 42 words | ||
| 25 | |||
| 26 | A [terminal emulator](https://en.wikipedia.org/wiki/Terminal_emulator) | ||
| 27 | is a program that displays text, usually coming from a | ||
| 28 | [shell](https://en.wikipedia.org/wiki/Shell_(computing)). | ||
| 29 | The shell reads text, normally entered by the user, and | ||
| 30 | interprets it. If this text instructs it to run another program, it | ||
| 31 | spawns a new [process](https://en.wikipedia.org/wiki/Process_(computing)) | ||
| 32 | for it. | ||
| 33 | |||
| 34 | ## Foreground and background jobs | ||
| 35 | |||
| 36 | A *job* is an entity that runs in the shell when you issue a command. | ||
| 37 | A job can consist of more than one process, for example if you | ||
| 38 | run multiple commands in a | ||
| 39 | [pipeline](https://en.wikipedia.org/wiki/Pipeline_(Unix)). | ||
| 40 | When you try to close a shell, it usually warns you if you have | ||
| 41 | running jobs *attached* to it, since it will *kill* them before | ||
| 42 | it closes - that might depend on the shell's configuration and | ||
| 43 | launch options, though. | ||
| 44 | |||
| 45 | When you run a program by typing its name of in a shell, say a text | ||
| 46 | editor like vi, this program "takes over" the shell. You can't run | ||
| 47 | any other command until this program terminates - or so it seems. | ||
| 48 | This happens also with most GUI programs, like firefox or gedit: | ||
| 49 | if you run them from a shell you will see some log messages, but | ||
| 50 | the shell is otherwise useless. This is the intendend behavior, and | ||
| 51 | this job is said to be running in the *foreground*. At any time | ||
| 52 | there can be at most one foreground job in a given shell. | ||
| 53 | |||
| 54 | If you have read my previous | ||
| 55 | [blog entry on the shell](../2022-09-13-sh-1), you should know that | ||
| 56 | you can launch a command in the *background* by adding an `&` | ||
| 57 | at the end of the line. Background jobs do not "block" the shell, | ||
| 58 | but they still use it to print their output. | ||
| 59 | |||
| 60 | So jobs can be running in the foreground or in the background of a | ||
| 61 | shell. There is also a third possible state for a shell's job: it | ||
| 62 | can be *suspended*. On most UNIX shells you can suspend a foreground | ||
| 63 | job by pressing `Ctrl`+`Z`. Try it: if you open `vi`, or any other | ||
| 64 | terminal-based program, and press `Ctrl`+`Z`, you are sent back to | ||
| 65 | a command prompt. This is even more fun with a graphical application: | ||
| 66 | its whole window becomes unresponsive and you can't even close it! | ||
| 67 | (Ok, I admit my definition of "fun" might be... unusual) | ||
| 68 | |||
| 69 | ## Full job control | ||
| 70 | |||
| 71 | So far we have seen how to run commands (jobs) in the foreground | ||
| 72 | (default behavior) or in the background (using `&`), and how to | ||
| 73 | suspend the job in the foreground (with Ctrl+Z). But we can do more. | ||
| 74 | |||
| 75 | To get an overview of the jobs attached to the current shell, you | ||
| 76 | can use the `jobs` command. If you run it while you have some | ||
| 77 | backgrounded or suspended jobs, you'll something like this: | ||
| 78 | |||
| 79 | ``` | ||
| 80 | [3] + Suspended vi | ||
| 81 | [2] - Suspended cat | ||
| 82 | [1] Running ./git/nissy/nissy | ||
| 83 | ``` | ||
| 84 | |||
| 85 | The number in brackets is the job's *ID*. It is followed by the | ||
| 86 | job's status (Done, Running, Suspended or Stopped) and the command | ||
| 87 | that started the job. If you use the `-l` option you'll get the | ||
| 88 | job's *process ID*, or PID, too. | ||
| 89 | |||
| 90 | You can use this information to change a job's status with the | ||
| 91 | `fg` and `bg` builtins. For example, typing | ||
| 92 | |||
| 93 | ``` | ||
| 94 | $ fg %job_id | ||
| 95 | ``` | ||
| 96 | |||
| 97 | makes a currently backgrounded or suspended job run in the foreground. | ||
| 98 | Similarly | ||
| 99 | |||
| 100 | ``` | ||
| 101 | $ bg %job_id | ||
| 102 | ``` | ||
| 103 | |||
| 104 | makes a currently suspended job run in the background. As far as I | ||
| 105 | know, there is no way to tell the job running in the foregroung to | ||
| 106 | pass to the background - you have to suspend it first, and then use | ||
| 107 | `bg`. | ||
| 108 | |||
| 109 | You can replace `%job_id` with the job's PID (without percent | ||
| 110 | symbol) or with `%string`, where `string` is the beginning of the | ||
| 111 | job's name. If you call `fg` or `bg` without any argument, the job | ||
| 112 | marked by a `+` in the jobs list is selected. You can select the | ||
| 113 | job marked by a `-` with `%-` | ||
| 114 | |||
| 115 | All of this is summed up in the following diagram: | ||
| 116 | |||
| 117 |  | ||
| 118 | |||
| 119 | *Picture generated with [tikz](https://github.com/pgf-tikz/pgf) | ||
| 120 | ([code, 1.2Kb](jobs-diagram.tex), [pdf, 27.3Kb](jobs-diagram.pdf)). | ||
| 121 | Do you know a better (simpler) tool or language to generate svg | ||
| 122 | graphics and diagrams programmatically? Let me know!* | ||
| 123 | |||
| 124 | You may have noticed that [kill(1)](http://man.openbsd.org/kill) | ||
| 125 | makes an appearance. I have not talked about it yet, and I won't | ||
| 126 | go over it in detail in this post, but to put it briefly you can | ||
| 127 | use `kill` to send certain [signals](http://man.openbsd.org/signal) | ||
| 128 | to a process or job - such as `SIGSTOP` to suspend and `SIGTERM` to | ||
| 129 | terminate. This is what pressing a Ctrl+Z or Ctrl+C actually does | ||
| 130 | under the hood. | ||
| 131 | |||
| 132 | ## Conclusion | ||
| 133 | |||
| 134 | With just a few simple bultins and keyboard sortcuts, the UNIX shell | ||
| 135 | gives some good flexibility in managing running jobs. If, like me, | ||
| 136 | you run most of your shells in a graphical terminal emulator or in | ||
| 137 | a tmux session, you can already get all the flexibility you want | ||
| 138 | by opening a new terminal window. But the ability to suspend jobs | ||
| 139 | and resume them later might be something new. Moreover, you might | ||
| 140 | find yourself in a situation where spawning a new window is not an | ||
| 141 | option - for example if you are connected to a remote machine via | ||
| 142 | ssh and you forgot to run tmux when you logged in. | ||
| 143 | |||
| 144 | I hope you found this post interesting. I certainly enjoyed | ||
| 145 | writing it, and I learnt a couple of new tricks in the process. | ||
diff --git a/src/blog/2023-02-25-job-control/jobs-diagram.pdf b/src/blog/2023-02-25-job-control/jobs-diagram.pdf new file mode 100644 index 0000000..a2e497b --- /dev/null +++ b/src/blog/2023-02-25-job-control/jobs-diagram.pdf | |||
| Binary files differ | |||
diff --git a/src/blog/2023-02-25-job-control/jobs-diagram.png b/src/blog/2023-02-25-job-control/jobs-diagram.png new file mode 100644 index 0000000..484e7b9 --- /dev/null +++ b/src/blog/2023-02-25-job-control/jobs-diagram.png | |||
| Binary files differ | |||
diff --git a/src/blog/2023-02-25-job-control/jobs-diagram.tex b/src/blog/2023-02-25-job-control/jobs-diagram.tex new file mode 100644 index 0000000..0a919db --- /dev/null +++ b/src/blog/2023-02-25-job-control/jobs-diagram.tex | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | \documentclass[crop, tikz]{standalone} | ||
| 2 | \usepackage{tikz} | ||
| 3 | |||
| 4 | \begin{document} | ||
| 5 | \begin{tikzpicture} | ||
| 6 | \usetikzlibrary{arrows.meta} | ||
| 7 | |||
| 8 | % Just a workaround to leave some space around the diagram | ||
| 9 | \filldraw[color=white,fill=white] (-8,-9) rectangle (8,1); | ||
| 10 | |||
| 11 | % Boxes | ||
| 12 | \newcommand{\tbox}[3]{ | ||
| 13 | \node[draw, rounded corners, text centered, text width=3cm] | ||
| 14 | (#1) at (#2) {\bf #3} | ||
| 15 | ; | ||
| 16 | } | ||
| 17 | \tbox {top} {0,0} {Job not running} | ||
| 18 | \tbox {left} {-6,-4} {Job running in the background} | ||
| 19 | \tbox {right} {6,-4} {Job running in the foreground} | ||
| 20 | \tbox {bottom} {0,-8} {Job suspended} | ||
| 21 | |||
| 22 | % Arrows | ||
| 23 | \newcommand{\arr}[4]{ | ||
| 24 | \draw[-{Latex[length=3mm]}, ultra thick] | ||
| 25 | (#1) edge[#4] node[fill=white] {\texttt{#3}} (#2) | ||
| 26 | ; | ||
| 27 | } | ||
| 28 | \arr {top} {left} {command \&} {bend right} | ||
| 29 | \arr {left} {top} {kill \%job} {bend right} | ||
| 30 | \arr {left} {bottom} {kill -STOP \%job} {bend right} | ||
| 31 | \arr {bottom} {left} {bg \%job} {bend right} | ||
| 32 | \arr {bottom} {right} {fg \%job} {bend left} | ||
| 33 | \arr {right} {bottom} {Ctrl+Z} {bend left} | ||
| 34 | \arr {right} {top} {Ctrl+C} {bend left} | ||
| 35 | \arr {top} {right} {command} {bend left} | ||
| 36 | \arr {left} {right} {fg \%job} {} | ||
| 37 | \end{tikzpicture} | ||
| 38 | \end{document} | ||
diff --git a/src/blog/blog.md b/src/blog/blog.md index d6ce61d..8bd57ea 100644 --- a/src/blog/blog.md +++ b/src/blog/blog.md | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | 5 | ||
| 6 | ## 2023 | 6 | ## 2023 |
| 7 | 7 | ||
| 8 | * 2023-02-25 [Job control: one shell is all you need](2023-02-25-job-control) | ||
| 8 | * 2023-01-28 [The year of the Windows desktop](2023-01-28-windows-desktop) | 9 | * 2023-01-28 [The year of the Windows desktop](2023-01-28-windows-desktop) |
| 9 | * 2023-01-11 [Aaron Swartz](2023-01-11-aaron-swartz) | 10 | * 2023-01-11 [Aaron Swartz](2023-01-11-aaron-swartz) |
| 10 | 11 | ||
diff --git a/src/blog/feed.xml b/src/blog/feed.xml index 9bbb571..88f547b 100644 --- a/src/blog/feed.xml +++ b/src/blog/feed.xml | |||
| @@ -9,6 +9,13 @@ Thoughts about software, computers and whatever I feel like sharing | |||
| 9 | </description> | 9 | </description> |
| 10 | 10 | ||
| 11 | <item> | 11 | <item> |
| 12 | <title>Job control: one shell is all you need</title> | ||
| 13 | <link>https://sebastiano.tronto.net/blog/2023-02-25-job-control</link> | ||
| 14 | <description>Job control: one shell is all you need</description> | ||
| 15 | <pubDate>2023-02-25</pubDate> | ||
| 16 | </item> | ||
| 17 | |||
| 18 | <item> | ||
| 12 | <title>The year of the Windows desktop</title> | 19 | <title>The year of the Windows desktop</title> |
| 13 | <link>https://sebastiano.tronto.net/blog/2023-01-28-windows-desktop</link> | 20 | <link>https://sebastiano.tronto.net/blog/2023-01-28-windows-desktop</link> |
| 14 | <description>The year of the Windows desktop</description> | 21 | <description>The year of the Windows desktop</description> |
