Search code examples
linuxbashwhile-loopembedded-linuxdd

How to know when dd has finished


I have a issue with the dd comand. I use it in a while like this:

while c=$(dd count=1000 bs=1 2>/dev/null) ;do

    echo -n "$c" > /dev/ttyO5
done < $FILE

And it works like charm, the only problem is that once the file is read completely, it doesnt stop the while, it stays there stalled. How could I make the while to stop once the dd read all the file?

BTW: Note my machine is embed linux, it doesnt have all the comands and tools as a normal ubuntu machine would have.

Thanks

Output dd --version

BusyBox v1.20.2 (MUSE) multi-call binary.

Usage: dd [if=FILE] [of=FILE] [bs=N] [count=N] [skip=N]
        [seek=N]

Copy a file with converting and formatting

        if=FILE         Read from FILE instead of stdin
        of=FILE         Write to FILE instead of stdout
        bs=N            Read and write N bytes at a time
        count=N         Copy only N input blocks
        skip=N          Skip N input blocks
        seek=N          Skip N output blocks

Numbers may be suffixed by c (x1), w (x2), b (x512), kD (x1000), k (x1024),
MD (x1000000), M (x1048576), GD (x1000000000) or G (x1073741824)

Solution

  • Note

    • '\0' will be lost after assigning to a variable.
    • '\\' may keep its special meaning depending on version of echo : try echo '\n'

    Status can be retrieved reading from stderr

    dd count=1000 bs=1 </dev/null
    0+0 records in
    0+0 records out
    

    So

    while
        c=$(dd ... 2>errorfile); 
        read line <errorfile;   # read the first line of error
        [[ $line != 0+0* ]];    # break while if line begins with 0+0
    do
        ...
    done
    

    It's slightly different from checking from length of c

    c=$(dd count=1 bs=1 </dev/null)
    echo "${#c}"
    
    
    c=$(dd count=1 bs=1 <<<$'\0')
    echo "${#c}"
    

    because in the last case a NUL character was read whereas in the previous no character were read.

    EDIT: following demonstrates that it works but is very slow :

    for x in {{0..9},{a..f}}{{0..9},{a..f}}; do printf "\x$x"; done |
    while
        c=$(dd count=1 bs=1 2>errfile;echo .); c=${c%.}
        read line <errfile
        [[ $line != 0+0* ]]
    do
        if [[ $c = '' ]]; then printf "\0"; else echo -n -E "$c"; fi
    done | od -c