5

I'm learning Linux. Came upon the idea that a process can be attached to a terminal. What does it mean to attach a process to a terminal (TTY) and why would I want to do it?

slm
  • 369,824
flashburn
  • 661

1 Answers1

8

NOTE: For a good primer on job control in Unix I'd direct you to the Wikipedia page on the topic - Job control (Unix).


Attached terminal?

The phrase, "attached to terminal", is typically what you'll hear when talking about jobs in a shell context. But it does have other meanings. the phrase "attach a process to a terminal" can also mean using a tool such as gdb or strace or lsof to attach to a specific process ID (PID) and list information or monitor it.

I'll discuss both, but to start, I'm going to cover job queues, since I suspect that's the one you're looking for.

Background - job queues

In Unix like operating systems, you'll typically see the concept of jobs. In most Unix like operating systems that I've used they all generally work in a similar fashion. That is, they can be backgrounded and assigned a number in a queue (job queue), and they can be acted on from the context of their number in this job queue.

To put something into the job queue, they typically call this act, backgrounding. When you resume a job that's been backgrounded, you call this foregrounding. The commands to do this are bg and fg typically. You can also put jobs into the background immediately using the ampersand & at the end of any command you run.

Examples

jobs

$ sleep 2 &
[1] 19189

Here I'm running a sleep command for 2 seconds and backgrounding it. The output immediately gives you useful info, such as the job queue number ([1]) and the process ID of the backgrounded job, 19189.

When this job eventually terminates it'll print this type of message in the terminal from where it ran:

$
[1]+  Done                    sleep 2

foreground & background

To act on jobs that have been backgrounded:

$ sleep 20 &
[1] 19207

$ fg
sleep 20
^C

Here I've sent a job to the background (&), then brought it back to the foreground (fg) and then killed it with the Ctrl+C (^C) command.

If we had multiple backgrounded jobs:

$ sleep 20 &
[1] 19224
$ sleep 20 &
[2] 19225
$ sleep 20 &
[3] 19226
$ jobs
[1]   Running                 sleep 20 &
[2]-  Running                 sleep 20 &
[3]+  Running                 sleep 20 &

We can see them with the jobs command. Notice the little + and - next to #3 and #2. If I run the fg command without specifying a job queue number, I'll get the last job that was put into the job queue (+). For example:

$ fg
sleep 20
^C

$ jobs
[1]-  Running                 sleep 20 &
[2]+  Running                 sleep 20 &

killing

You can use the job queue numbers to act on the jobs. One such method is to kill them. To refer to a job queue's number, you prefix them with a % when you want to refer to them with other commands, such as kill. You can of course kill multiple all at once, or just one:

$ kill %3 %4 %5
$ jobs
[3]   Terminated              sleep 20
[4]   Terminated              sleep 20
[5]-  Terminated              sleep 20
[6]+  Running                 sleep 20 &

Background attaching to a PID

To attach a process to a terminal could also mean the following. Here's my shell's PID:

$ echo $$
23543

In another shell I'm running strace and connecting to this process to see what system calls it's making:

$ strace -p 23543
strace: Process 23543 attached
read(0,

NOTE: Here you can see that it's waiting in a read for commands. That's what terminals/shells do.

Here we can see that I've started to type the command ls within it, and the shell is echoing this backout to the shell in the form of write() system calls.

read(0, "l", 1)                         = 1
rt_sigprocmask(SIG_BLOCK, [INT], [], 8) = 0
write(2, "l", 1)                        = 1
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8)  = 0
read(0, "s", 1)                         = 1
rt_sigprocmask(SIG_BLOCK, [INT], [], 8) = 0
write(2, "s", 1)                        = 1
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8)  = 0
read(0,

This is another form of attaching a process to a terminal.

Other forms

One of the more obscure references to attaching a process to a terminal could be assumed here as well. This U&L Q&A titled: How to attach terminal to detached process? covers that one in all its forms.

The basic premise with this form of the reference, is that you've taken a backgrounded job, and "disconnected" it from the current shell. You do this using the commands nohup or disown.

Once a process has been disowned, you can no longer use the jobs, fg or bg commands to act on it. It's no longer associated to your current shell's PID.

The traditional method for re-acquiring a previously disowned process is to use a tool such as reptyr, which will re-attach a PID to your existing shell. For example say we start 2 jobs and nohup them:

$ nohup sleep 200 &
[1] 19720
$ nohup sleep 200 &
[2] 19721

Still attached to our terminal's job queue, let's disown them:

$ jobs
[1]-  Running                 nohup sleep 200 &
[2]+  Running                 nohup sleep 200 &
$ disown -a

Now they're gone:

$ jobs
$

They're still listed as being children of our original shell's PID (23543):

$ ps -eaf|grep -E "19720|19721"
vagrant  19720 23543  0 18:29 pts/1    00:00:00 sleep 200
vagrant  19721 23543  0 18:29 pts/1    00:00:00 sleep 200

Now if we exit and log back in, we'll see that these processes are now listed as being parents of the main PID, 1:

$ ps -eaf|grep -E "19720|19721"
vagrant  19720     1  0 18:29 ?        00:00:00 sleep 200
vagrant  19721     1  0 18:29 ?        00:00:00 sleep 200

These processes were able to do this because we nohuped them and disown'ed them. Let's reattach one of them:

$ reptyr -s 19720
[-] Timed out waiting for child stop.

^C

NOTE: In the above, I've reattached PID 19720 to my shell and then killed it via Ctrl+C. We can see it's gone now:

$ ps -eaf|grep -E "19720|19721"
vagrant  19721     1  0 18:29 ?        00:00:00 sleep 200
slm
  • 369,824
  • If someone edits the answer later, remember to change "parents of the main PID" to "children of the main PID". You need 10 char minimum to accomplish an edit (not 8). – Jose_X May 15 '21 at 10:08