sebastiano.tronto.net

Source files and build scripts for my personal website
git clone https://git.tronto.net/sebastiano.tronto.net
Download | Log | Files | Refs | README

commit 6174aa76ee061818a8ca6b0d952e90257ca3b5d4
parent d0221b3325c5e0b206d744d1ffcae0fbcb96ec2a
Author: Sebastiano Tronto <sebastiano@tronto.net>
Date:   Sat, 25 Feb 2023 15:18:18 +0100

Added blog post

Diffstat:
Asrc/blog/2023-02-25-job-control/job-control.md | 145+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/blog/2023-02-25-job-control/jobs-diagram.pdf | 0
Asrc/blog/2023-02-25-job-control/jobs-diagram.png | 0
Asrc/blog/2023-02-25-job-control/jobs-diagram.tex | 38++++++++++++++++++++++++++++++++++++++
Msrc/blog/blog.md | 1+
Msrc/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 @@ -0,0 +1,145 @@ +# Job control: one shell is all you need + +If you work in a graphical desktop environment, you are most likely +used to multi-tasking. You can listen to music while you type your +blog posts, browse the web while your code compiles, and so on. + +But what if you are interacting with your machine via a command +line? Sure, you can use a +[terminal multiplexer](https://en.wikipedia.org/wiki/Terminal_multiplexer) +like [tmux](https://tmux.github.io). +But what if you forgot to run it before starting your tasks? And now +you are updating your packages and the shell is locked?! What a nightmare! + +Luckily, the UNIX shell has a job control system that allows you +to run multiple tasks at the same time. What I explain in this post +has been tested on ksh on OpenBSD, but should work in the same way +on Linux or any UNIX-like OS with a POSIX-compatible shell - except +perhaps for the key combinations to suspend or kill a job. + +This post is not meant to be an introduction to what the shell is, +but it is worth spending a few words to clear up some common (and +understandable) confusion. I'll keep them really *a few*. + +## The terminal vs the shell, in 42 words + +A [terminal emulator](https://en.wikipedia.org/wiki/Terminal_emulator) +is a program that displays text, usually coming from a +[shell](https://en.wikipedia.org/wiki/Shell_(computing)). +The shell reads text, normally entered by the user, and +interprets it. If this text instructs it to run another program, it +spawns a new [process](https://en.wikipedia.org/wiki/Process_(computing)) +for it. + +## Foreground and background jobs + +A *job* is an entity that runs in the shell when you issue a command. +A job can consist of more than one process, for example if you +run multiple commands in a +[pipeline](https://en.wikipedia.org/wiki/Pipeline_(Unix)). +When you try to close a shell, it usually warns you if you have +running jobs *attached* to it, since it will *kill* them before +it closes - that might depend on the shell's configuration and +launch options, though. + +When you run a program by typing its name of in a shell, say a text +editor like vi, this program "takes over" the shell. You can't run +any other command until this program terminates - or so it seems. +This happens also with most GUI programs, like firefox or gedit: +if you run them from a shell you will see some log messages, but +the shell is otherwise useless. This is the intendend behavior, and +this job is said to be running in the *foreground*. At any time +there can be at most one foreground job in a given shell. + +If you have read my previous +[blog entry on the shell](../2022-09-13-sh-1), you should know that +you can launch a command in the *background* by adding an `&` +at the end of the line. Background jobs do not "block" the shell, +but they still use it to print their output. + +So jobs can be running in the foreground or in the background of a +shell. There is also a third possible state for a shell's job: it +can be *suspended*. On most UNIX shells you can suspend a foreground +job by pressing `Ctrl`+`Z`. Try it: if you open `vi`, or any other +terminal-based program, and press `Ctrl`+`Z`, you are sent back to +a command prompt. This is even more fun with a graphical application: +its whole window becomes unresponsive and you can't even close it! +(Ok, I admit my definition of "fun" might be... unusual) + +## Full job control + +So far we have seen how to run commands (jobs) in the foreground +(default behavior) or in the background (using `&`), and how to +suspend the job in the foreground (with Ctrl+Z). But we can do more. + +To get an overview of the jobs attached to the current shell, you +can use the `jobs` command. If you run it while you have some +backgrounded or suspended jobs, you'll something like this: + +``` +[3] + Suspended vi +[2] - Suspended cat +[1] Running ./git/nissy/nissy +``` + +The number in brackets is the job's *ID*. It is followed by the +job's status (Done, Running, Suspended or Stopped) and the command +that started the job. If you use the `-l` option you'll get the +job's *process ID*, or PID, too. + +You can use this information to change a job's status with the +`fg` and `bg` builtins. For example, typing + +``` +$ fg %job_id +``` + +makes a currently backgrounded or suspended job run in the foreground. +Similarly + +``` +$ bg %job_id +``` + +makes a currently suspended job run in the background. As far as I +know, there is no way to tell the job running in the foregroung to +pass to the background - you have to suspend it first, and then use +`bg`. + +You can replace `%job_id` with the job's PID (without percent +symbol) or with `%string`, where `string` is the beginning of the +job's name. If you call `fg` or `bg` without any argument, the job +marked by a `+` in the jobs list is selected. You can select the +job marked by a `-` with `%-` + +All of this is summed up in the following diagram: + +![Diagram showing how to change the status of a job](jobs-diagram.png) + +*Picture generated with [tikz](https://github.com/pgf-tikz/pgf) +([code, 1.2Kb](jobs-diagram.tex), [pdf, 27.3Kb](jobs-diagram.pdf)). +Do you know a better (simpler) tool or language to generate svg +graphics and diagrams programmatically? Let me know!* + +You may have noticed that [kill(1)](http://man.openbsd.org/kill) +makes an appearance. I have not talked about it yet, and I won't +go over it in detail in this post, but to put it briefly you can +use `kill` to send certain [signals](http://man.openbsd.org/signal) +to a process or job - such as `SIGSTOP` to suspend and `SIGTERM` to +terminate. This is what pressing a Ctrl+Z or Ctrl+C actually does +under the hood. + +## Conclusion + +With just a few simple bultins and keyboard sortcuts, the UNIX shell +gives some good flexibility in managing running jobs. If, like me, +you run most of your shells in a graphical terminal emulator or in +a tmux session, you can already get all the flexibility you want +by opening a new terminal window. But the ability to suspend jobs +and resume them later might be something new. Moreover, you might +find yourself in a situation where spawning a new window is not an +option - for example if you are connected to a remote machine via +ssh and you forgot to run tmux when you logged in. + +I hope you found this post interesting. I certainly enjoyed +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 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 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 @@ -0,0 +1,38 @@ +\documentclass[crop, tikz]{standalone} +\usepackage{tikz} + +\begin{document} +\begin{tikzpicture} +\usetikzlibrary{arrows.meta} + +% Just a workaround to leave some space around the diagram +\filldraw[color=white,fill=white] (-8,-9) rectangle (8,1); + +% Boxes +\newcommand{\tbox}[3]{ + \node[draw, rounded corners, text centered, text width=3cm] + (#1) at (#2) {\bf #3} + ; +} +\tbox {top} {0,0} {Job not running} +\tbox {left} {-6,-4} {Job running in the background} +\tbox {right} {6,-4} {Job running in the foreground} +\tbox {bottom} {0,-8} {Job suspended} + +% Arrows +\newcommand{\arr}[4]{ + \draw[-{Latex[length=3mm]}, ultra thick] + (#1) edge[#4] node[fill=white] {\texttt{#3}} (#2) + ; +} +\arr {top} {left} {command \&} {bend right} +\arr {left} {top} {kill \%job} {bend right} +\arr {left} {bottom} {kill -STOP \%job} {bend right} +\arr {bottom} {left} {bg \%job} {bend right} +\arr {bottom} {right} {fg \%job} {bend left} +\arr {right} {bottom} {Ctrl+Z} {bend left} +\arr {right} {top} {Ctrl+C} {bend left} +\arr {top} {right} {command} {bend left} +\arr {left} {right} {fg \%job} {} +\end{tikzpicture} +\end{document} diff --git a/src/blog/blog.md b/src/blog/blog.md @@ -5,6 +5,7 @@ ## 2023 +* 2023-02-25 [Job control: one shell is all you need](2023-02-25-job-control) * 2023-01-28 [The year of the Windows desktop](2023-01-28-windows-desktop) * 2023-01-11 [Aaron Swartz](2023-01-11-aaron-swartz) diff --git a/src/blog/feed.xml b/src/blog/feed.xml @@ -9,6 +9,13 @@ Thoughts about software, computers and whatever I feel like sharing </description> <item> +<title>Job control: one shell is all you need</title> +<link>https://sebastiano.tronto.net/blog/2023-02-25-job-control</link> +<description>Job control: one shell is all you need</description> +<pubDate>2023-02-25</pubDate> +</item> + +<item> <title>The year of the Windows desktop</title> <link>https://sebastiano.tronto.net/blog/2023-01-28-windows-desktop</link> <description>The year of the Windows desktop</description>