0

I've been writing a script to clear areas of disk storage devices, but have been running into many issues.

Consider the following cases:

  1. Direct, Non-Piped - Directly executing the command

    dd if=/dev/zero of=/dev/sdX bs=512k seek=256 count=4096 conv=notrunc iflag=count_bytes,nocache,fullblock oflag=seek_bytes 2> /tmp/output & dd_pid=$!
    

    Expected Behavior Typing this directly in terminal / running directly through a script works perfectly fine.

  2. Indirect (Variable), Non-Piped - Executing the command through a variable

    dd_command="dd if=/dev/zero of=/dev/sdX bs=512k seek=256 count=4096 conv=notrunc iflag=count_bytes,nocache,fullblock oflag=seek_bytes"
    $dd_command 2> /tmp/output & dd_pid=$!
    

    Expected Behavior. Also works perfectly fine, just as 1.

  3. Direct, Piped - Attempting to write all 1s to the disk area

    tr '\000' '\377' < /dev/zero | dd of=/dev/sdX bs=512k count=4096 conv=notrunc iflag=count_bytes,nocache,fullblock 2> /tmp/output & dd_pid=$!
    

    Secondary Issues While this command performs its primary task of writing to the disk to completion, it hangs/terminates after a short period if the seek / oflag=seek_bytes parameters are present from 1..

  4. Indirect (Variable), Piped -

    dd_command="tr '\000' '\377' < /dev/zero | dd of=/dev/sdX bs=512k count=4096 conv=notrunc iflag=count_bytes,nocache,fullblock"
    $dd_command 2> /tmp/output & dd_pid=$!
    

    PRIMARY ISSUE Regardless of flags, and I've tried removing all of them and even the seek and count parameters, this command will always fail after a few minutes/process terminated. It seems because I stored this command into a variable and then execute the command by calling the variable, as opposed to directly calling the command.

Questions

  1. Why does calling this type of piped command via a variable instead of direct result in a crash?
  2. Why do the additional flags in the piped command cases cause the command to fail?

Other Notes

Outputs to the file in all cases were performed by calling kill -USR1 $dd_pid. This worked as intended for the cases 1. and 2., but for the cases that didn't, would be an additional cause (even earlier termination of the program) if this signal was sent to the process. It was not required to see the termination of the program though, but unclear why it would terminate the program at all.

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
rvijay007
  • 1,357
  • 12
  • 20

1 Answers1

3

This is the wrong way to store a complex command.

Parsing is done before any parameter expansions. Although an unquoted parameter expansion undergoes word-splitting, the result is not reparsed. A | is just another argument to tr, not a shell metacharacter that defines a pipeline between tr and dd.

If you want to store complicated commands, use a function.

$ dd_command () {
>  tr '\000' '\377' < /dev/zero | 
>    dd of=/dev/sdX bs=512k count=4096 conv=notrunc iflag=count_bytes,nocache,fullblock
> }
>
$ dd_command 2> /tmp/output & dd_pid=$!

This also simplifies quoting, as the body of the function doesn't have to be quoted as the RHS of a parameter assignment needs to be.

chepner
  • 497,756
  • 71
  • 530
  • 681