Sunday, September 12, 2021

Be very careful with echo on Windows

Recently one of my users of Jacksum reported a strange behavior if echo is used on Microsoft Windows.

For those who don't know: Jacksum is a data integrity tool which can (not only) calculate and verify hash values. For more information go to https://jacksum.net

So the report (which was sent privately to me) was this:

jacksum -q "txt:Hello World!"
d0e47486bbf4c16acac26f8b653592973c1362909f90262877089f9c8a4536af

that is correct, but if Jacksum reads from stdin and echo on Windows is used, it returns a completely different hash:

echo "Hello World!" | jacksum -
61ab266cecda9b9885aedbbb5b3d9914738cec74930301ec7b68312b6b436b8b <stdin>

Is Jacksum right?

Yes, Jacksum is right. The problem is with the echo command on Windows!

I started Jacksum with "--verbose summary" which gives us additional information:

echo "Hello World!" | jacksum --verbose summary -
61ab266cecda9b9885aedbbb5b3d9914738cec74930301ec7b68312b6b436b8b <stdin>

Jacksum: files read successfully: 1
Jacksum: files read with errors: 0
Jacksum: total bytes read: 17
Jacksum: total bytes read (human readable): 17 bytes

Jacksum: elapsed time: 139 ms

As you can see, Jacksum have read 17 bytes from stdin (the 3rd line of the summary). "Hello World!" (without quotes) are just 12 characters, what are the other 5 characters?

I pasted the output of echo to a file ...

echo "Hello World!" > hello.txt

and loaded the file in a hex editor (https://hexed.it will work perfectly well for that task)

As you can see, the Windows echo

- does not only transfers the Hello World! to the pipe (Hello World! => 12 bytes), but also ...
- it appends the Windows carriage return, line feed chars (0x0D, 0x0A => 2 bytes) which is expected on Windows
- it doesn't strip the quotes (2x" => 2 bytes) - which is probably not known to everybody, and
- ATTENTION!: it doesn't strip the blank that is between the 2nd quote (") and the redirection sign (>) => 1 byte

That means a 

echo "Hello World!"        > hello2.txt

would even add more blanks to the output.



And even if we would do this:

echo Hello World!> hello3.txt

the CR LF will always be there, because there is no -n option (which GNU/Linux and macOS have for example).

So the workaround on Microsoft Windows 10 we found is this:

echo | set /p="Hello World!" | jacksum -
d0e47486bbf4c16acac26f8b653592973c1362909f90262877089f9c8a4536af <stdin>

which produces the expected hash.

Mission completed.

BTW, on GNU/Linux and macOS you can still use echo as expected, but you need to use single quotes rather than double quotes, because the ! has a special meaning on many *nix-shells:

$ echo -n 'Hello World!' | jacksum -
d0e47486bbf4c16acac26f8b653592973c1362909f90262877089f9c8a4536af <stdin>

Cheers,
Johann

No comments:

Post a Comment