How to check the progress of dd using proc filesystem

On Sunday 29th April 2012, I have described How to check the progress of dd using User-defined signal 1. Today, I will extend this topic further using proc filesystem.

The idea

This technique reads and parses IO statistics file for running dd process.

This file is described in detail in section 3.3 [/proc/<pid>/io - Display the IO accounting fields] of the /proc filesystem documentation.

Print how much data has been written to the file or device

$ ./dd.sh if=infile of=outfile
   1 GB

This is the simplest solution as it only prints how much data has been written in human readable form.

#!/bin/sh
# print how much data has been written to the file or device
# dd output will overwrite printed data at the end
#
# sample usage:
# dd.sh if=infile of=outfile

# execute dd command in the background
$(which dd) $* &

# read process ID
process=$!

# execute until the process exists
while [ "$(kill -0 $process 2>/dev/null; echo $?)" -eq "0" ]; do
  if [ -e "/proc/${process}/io" ]; then
    # get number of written bytes
    written_data=$(cat /proc/${process}/io | awk '/wchar/ {print $2}')

    # convert it to human readable form
    unit="B"                                     # bytes

    if [ "$written_data" -gt "1024" ]; then
      written_data=$(expr $written_data / 1024)  # kilobytes
      unit="KB"
    fi

    if [ "$written_data" -gt "1024" ]; then
      written_data=$(expr $written_data / 1024)  # megabytes
      unit="MB"
    fi

    if [ "$written_data" -gt "1024" ]; then
      written_data=$(expr $written_data / 1024)  # gigabytes
      unit="GB"
    fi

    if [ "$written_data" -gt "1024" ]; then
      written_data=$(expr $written_data / 1024)  # terabytes
      unit="TB"
    fi

    # print output
    printf "%4s %2s\r" ${written_data} ${unit}

    # wait 1 second
    sleep 1
  else
    break
  fi
done

Print how much data has been written to the file or device using percentage value

$ sh ./dds.sh test test2
  67 %

This shell script is different as it prints percentage value of written data. The most interesting part is that it needs to know file or device size in advance.

#!/bin/sh
# print how much data has been written to the file or device using percentage value
# dd output will overwrite printed data at the end
#
# sample usage:
# dds.sh infile outfile

# command arguments
file_from=$1
file_to=$2

# defaults settings
bs="20M"

if [ -e "$file_from" ]; then
  if [ -b "$file_from" ]; then
    file_from_size=$(blockdev --getsize64 $file_from)
  else
    file_from_size=$(stat --format "%s" $file_from)
  fi

  $(which dd) if=${file_from} of=${file_to} bs=${bs} &

  # read process ID
  process=$!

  # execute until the process exists
  while [ "$(kill -0 $process 2>/dev/null; echo $?)" -eq "0" ]; do
    if [ -e "/proc/${process}/io" ]; then
      # get number of written bytes
      written_data=$(cat /proc/${process}/io | awk '/wchar/ {print $2}')

      percent=$(expr 100 \* $written_data / $file_from_size)
      # convert it to human readable form

      # print output
      printf "%4s %%\r" ${percent}

      # wait 1 second
      sleep 1
    else
      break
    fi
  done
fi

Print how much data has been written to the file using percentage bar

$ sh ./ddb.sh test test2
  41 % [++++++++++++++++                        ]

This shell script uses technique described in How to create simple bar charts in terminal using awk blog post to print bar chart.

#!/bin/sh
# print how much data has been written to the file or device using percentage value
# dd output will overwrite printed data at the end
#
# sample usage:
# ddb.sh infile outfile

# command arguments
file_from=$1
file_to=$2

# defaults settings
bs="20M"

# character used to print bar chart
barchr="+"

# current min, max values
vmin=1
vmax=100

# range of the bar graph
dmin=1
dmax=40

if [ -e "$file_from" ]; then
  if [ -b "$file_from" ]; then
    file_from_size=$(blockdev --getsize64 $file_from)
  else
    file_from_size=$(stat --format "%s" $file_from)
  fi

  $(which dd) if=${file_from} of=${file_to} bs=${bs} &

  # read process ID
  process=$!

  # execute until the process exists
  while [ "$(kill -0 $process 2>/dev/null; echo $?)" -eq "0" ]; do
    if [ -e "/proc/${process}/io" ]; then
      # get number of written bytes
      written_data=$(cat /proc/${process}/io | awk '/wchar/ {print $2}')

      percent=$(expr 100 \* $written_data / $file_from_size)

      # generate output
      awk --assign dmin="$dmin" --assign dmax="$dmax" \
          --assign vmin="$vmin" --assign vmax="$vmax" \
          --assign percent="$percent" \
          --assign barchr="$barchr" \
          'BEGIN {
            x=int(dmin+(percent-vmin)*(dmax-dmin)/(vmax-vmin));
            printf "%4i %% [", percent
            for(i=1;i<=dmax;i++){if(i <= x) printf barchr; else printf " "};
            printf "]\r"
            if(x == dmax)
              printf "\033[0K"
          }'

      # wait 1 second
      sleep 1
    else
      break
    fi
  done
fi
Milosz Galazka's Picture

About Milosz Galazka

Milosz is a Linux Foundation Certified Engineer working for a successful Polish company as a system administrator and a long time supporter of Free Software Foundation and Debian operating system.

Gdansk, Poland https://sleeplessbeastie.eu