I'm trying the the Rust version of coreutils on my Windows 10 system. I renamed coreutils.exe to co.exe so that I can type less. od is the Windows version of the Linux command od [from linux man site = od - dump files in octal and other formats]. Here is my test.
PS C:\> co printf "asdf" | od -c
0000000 a s d f \r \n
0000006
PS C:\> co printf "asdf" | Set-Content -NoNewline out.txt; od -c out.txt
0000000 a s d f
0000004
PS C:\>
As you can see, PowerShell pipeline adds newline when passing to the next command. How to disable this behavior?
I also tested on a Linux system.
[user@server ~]$ printf abcd | od -c
0000000 a b c d
0000004
[user@server ~]$
Also, here is the result on a native cmd.exe.
C:\>co printf "asdf" | od -c
0000000 a s d f
0000004
C:\>
As you can see, both the Linux version and cmd.exe don't add such newline characters. @JosefZ mentioned that WSL also adds such character, which I haven't tested.
I just found the Format-Hex CmdLet from @Richard's answer. Here is another test:
PS C:\> co printf "asdf" | Format-Hex
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00000000 61 73 64 66 asdf
PS C:\>
I'm still confused about the various behaviors.
tl;dr
PowerShell's pipeline unexpectedly appends an extraneous newline to output piped to external programs; see GitHub issue #5974; as a workaround, delegate to cmd.exe /c on Windows, as shown at the bottom, to sh -c on Unix-like platforms.
The only exception is in PowerShell 7 v7.4+, if both the producer and the consumer of the pipeline are external programs, because PowerShell then doesn't act as an intermediary between the programs; in other words:
Your specific command would work as expected only in PowerShell 7.4+.
In Windows PowerShell (the legacy, ships-with-Windows, Windows-only edition of PowerShell whose latest and final version is 5.1), as well as in - now obsolete - PowerShell (Core) 7 versions up to 7.3.x, the following behaviors apply:
Even when piping between or from external programs, PowerShell acts as an intermediary in that it first decodes external-program output based on the character encoding stored in [Console]::OutputEncoding into .NET strings.
PowerShell (Core) 7.4+ no longer does that when piping between external programs, and using the |, the pipeline operator, now acts as a raw byte conduit between external programs, which means your problem would go away there - see this answer.
Important:
Do note that the problem only goes away if the input too is provided by an external program; piping a PowerShell-originated string to an external program is still subject to the unexpected appending of a newline - see next major bullet point.
Also, in general, note that decoding external-program output to .NET strings - by design and of necessity - is still and will continue to be performed when piping to PowerShell-native commands (rather than to external programs) as well as when using external-program output in the context of PowerShell expressions.
On piping (relaying) such decoded - or even PowerShell-originated - output to an(other) external program, PowerShell (re-)encodes the output using the encoding stored in the $OutputEncoding preference variable and - and this is the unexpected part - invariably appends a (platform-native) newline to the (last) input string passing through the pipeline.
E.g., on Windows "foo" | wsl od -c yields the following, showing that a Windows-format CRLF newline (\r\n) was unexpectedly appended (assumes that WSL is installed; irrelevant output line omitted):
0000000 f o o \r \n
Similarly, "foo" | od -c on any of the supported Unix-like platforms (Linux, macOS) shows that a Unix-format LF-only newline (\n) was appended.
0000000 f o o \n
This problematic behavior, which also still affects PowerShell (Core) 7 up to at least v7.5.x with PowerShell-originated (stringified) output, is the subject of GitHub issue #5974.
Note that piping to PowerShell-native commands or using external-program output as part of a PowerShell expression is not affected.
The workaround is to delegate the operation to cmd.exe, whose | operator always acts as a raw byte conduit:
Applied to your case:
cmd /c 'co printf "asdf" | od -c'
See this answer for details.