7

I trying to understand the manpage of the dd program, which mentions:

Sending a USR1 signal to a running 'dd' process makes it print I/O statistics to standard error and then resume copying.

         $ dd if=/dev/zero of=/dev/null& pid=$!
         $ kill -USR1 $pid; sleep 1; kill $pid

What does pid=$! mean?

Is this an assignment of a variable, which gets the pid of dd? And is eventually used in the $pid variable?

Also why do they use sleep and kill?

Is this the way to use -USR1?

Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
Aby W
  • 193
  • not an answer to understanding dd, but have you seen pv? for example: dd if=/dev/zero | pv | dd of=/dev/null, it also supports a progress bar... – mikejonesey Oct 24 '16 at 22:43

4 Answers4

7

dd if=/dev/zero of=/dev/null&

The trailing & means run the prefix command in background. (Disclaimer: This is oversimplified statement)

Refer to this:

$! is the PID of the most recent background command.

So pid=$! assign the most Recent background PID to variable pid, which is dd PID.

Also why they use sleep and kill?.

You need kill $pid (if not specified parameter, default signal for kill is TERM which is process termination) to terminate the dd process after you done testing, otherwise dd process may just stay in background and exhausting your CPU resources. Check your System Monitor of your platform to see.

Whereas Kill -USR1 $pid print I/O statistics, it doesn't terminate the process.

Without sleep 1 second, your dd process may get terminated by last command statement kill $pid** before have the chance to write statistics output to your terminal. The processes is synchronous but trap+write operation (kill -USR1 $pid) may slower than terminate operation (kill $pid). So sleep 1 second to delay the startup of kill $pid to ensure statistics output done printing.

This is the way to use -USR1?

Just man dd:

Sending a USR1 signal to a running 'dd' process makes it print I/O statistics to standard error and then resume copying.

And man 7 signal:

   SIGUSR1   30,10,16    Term    User-defined signal 1
   SIGUSR2   31,12,17    Term    User-defined signal 2

Combine both statements , you should understand USR1 is User-defined signal which is defined by dd to provide a way for user to interrupt it and print I/O statistics on the fly. It's program specific handler, it doesn't means you can kill -USR1 other_program_pid and expect statistics output.

Also you might interest about this: Why does SIGUSR1 cause process to be terminated?.

林果皞
  • 5,156
  • 3
  • 33
  • 46
6

This is just a demonstration to illustrate the use of the USR1 signal with dd.

dd if=/dev/zero of=/dev/null &

starts dd in the background, copying data from /dev/zero (which produces zeroes whenever a program reads from it) to /dev/null (which discards anything written to it). This provides a harmless instance of dd which can be used to experiment with — it doesn't use up any storage, and will keep on running as long as we want it to, which gives the user time to send signals to it.

pid=$!

stores the process identifier of the last background command ($!) in the variable pid.

kill -USR1 $pid

sends the USR1 signal to the process whose identifier is the value stored in the pid variable, the background dd in this case. When dd receives this signal, it prints out its current progress (the amount of data read and written) and continues copying.

sleep 1

waits one second.

kill $pid

sends the TERM signal to dd, which causes dd to exit. (There's no point in leaving the background dd running here.)

It would be more instructive to run this instead of the second line above:

kill -USR1 $pid; sleep 1; kill -USR1 $pid; kill $pid

This would output the progress twice, with one second in between, to show dd's progress; then kill dd without waiting.

For actual use, you'd specify appropriate inputs and outputs for the original dd command, and probably some other options too, and you wouldn't run the last kill — you'd wait for dd to finish of its own accord.

To answer your final question, this is how you send USR1 signals from a shell (or any other signal): you use kill with the signal you want to send, and the process identifiers (or job identifiers) of the processes you want to send the signal to. Other (non-POSIX) commands you can use are pkill and killall, when you want to find processes by name.

Stephen Kitt
  • 434,908
3

For most or all shells, $! is the process ID (also called PID) of the last process that the shell forked. The dd command got forked with the &, so that the pid=$! right after forking dd assigns dd process ID to the shell variable pid.

A process ID is a number used by Linux or Unix to refer to an address space with some code executing in it.

The kill program has an unintuitive name, because its purpose is to send signals (small, asynchronous messages) to processes. There are only a few signals, maybe 128 in total, they have both numbers and names. The "kill" signal is number 9, for example. USR1 is defined as number 10. So the kill -USR1 $pid sends signal 10 to the process numbered $pid. dd sometimes takes a long time to execute, so that's almost certainly the process ID of the dd command that got forked earlier, and ran in the background. The kill $pid command sends a TERM signal to that same process ID. TERM means "terminate". Well-written programs usually catch TERM, clean up what resources they have allocated and then exit.

I'm not entirely certain why you would run dd in the background, send a USR1 signal to it, wait 1 second, and then cause dd to deallocate all resources, and exit. The whole code fragment seems to assume that dd runs for a long time, which may not be true. I think there are race conditions in this code, and whatever the desired semantics, you may not actually get them.

  • I've been searching for a while now trying to find out an alternative util to "kill" whose purpose is to send signal to a process, not kill it. This is the first time I've read what I've been suspecting - that kill's purpose is to send signals, not necessarily to kill a process. Thanks for stating this - woulda searched longer. It's very stupid, but so much of programming is. – aaaaaa Jan 24 '24 at 00:25
1

If you are expecting dd command to run in foreground and display current progress status. try running command with status=progress flag:

sudo dd if=/dev/sda of=/dev/sdb status=progress

This will dynamically display the progress.

That's an extension of the GNU implementation of dd (added in version 8.24 released in 2015), also available in the dd implementation on FreeBSD since 12.0 (2018), but generally not other implementations including on other BSDs.