Some posts have showed how to display the command's progress. In order to calculate it, you'll need to see how much you've progressed. On BSD systems some commands, like dd(1), accept a SIGINFO signal, and will report their progress. On Linux systems some commands will respond similarly to SIGUSR1. If this facility is available, you can pipe your input through dd to monitor the number of bytes processed.
Alternatively, you can use lsof to obtain the offset of the file's read pointer, and thereby calculate the progress. A command like the following could do the trick.
lsof -o0 -o -p $PID |
awk '
BEGIN { CONVFMT = "%.2f" }
$4 ~ /^[0-9]+r$/ && $7 ~ /^0t/ {
offset = substr($7, 3)
fname = $9
"stat -f %z '\''" fname "'\''" | getline
len = $0
print fname, offset / len * 100 "%"
}
'
I've posted Linux and FreeBSD shell scripts on my blog.