New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Piping Text To An External Program Appends A Trailing Newline #5974
Comments
One point of clarity. in powershell (with /bin/echo -n "string" | openssl dgst -sha256 -hmac "authcode" result: bash (without /bin/echo "string" | openssl dgst -sha256 -hmac "authcode" result: |
Is the problem in cmd.exe and Bash? |
@markekraus Yes I have tried using echo and Write-Output with and without the -n / NoEnumerate but the hashs returned are always the same regardless what is used. |
You can get the (hopefully) full story and workarounds in this SO answer of mine, but the short of it is: As @markekraus has already stated, the PowerShell pipeline invariably appends a (platform-appropriate) trailing newline to strings when they're sent to external programs, which you can verify as follows (on a Unix platform):
The This is problematic, as is the general inability to pipe raw byte streams (see #1908, which addresses external-program-to-external-program piping, though sometimes you may even want to send raw bytes from a PowerShell command). |
@ThePieMonster: If you agree with my analysis, can you please change the title of this issue to something like "Piping text to an external program appends a trailing newline"? |
@mklement0 I updated the title as you suggested. |
@ThePieMonster: Thanks for updating the title. Unfortunately, Thus, you must use the following on Windows (my linked SO answer states limitations of this approach): cmd /c "<NUL set /p =`"string`"| ..." # NO space before | If you happen to have the GnuWin32 tools installed on Windows, you can use On Unix: sh -c "printf %s `"string`" | ..." |
@mklement0 Thanks for the suggestion. The below seems to do the trick for me to get PShell to not have the trailing newline which in turn responds with the same hash as in Linux. (Being careful to not have a space before | like suggested). cmd /c "<NUL set /p =`"string`"| openssl dgst -sha256 -hmac authcode" |
Maybe an |
Sidenote In case anyone landed here looking to get rid of the trailing newline from piped input, I was able to trim the newline from a one-line output command and pass it to the
|
This issue is about the inability to send a string as-is TO an external program, without having PowerShell append a trailing newline. In the opposite direction, FROM an external program, as in your example, you usually have the opposite problem: because PowerShell automatically splits output from external programs into an array of lines, you can't tell the difference between a given external program sending you just (In other words: strings come "pre-trimmed" with respect to trailing newlines, and the So we'd need both The raw native-exe-to-native-exe piping or native-exe-to-file-redirection (#1908) isn't implemented yet either. I don't know what the right solution is, but, as of PowerShell Core 7.0.0-preview.5, PowerShell and external (native) executables are separate worlds that can only communicate with one another if they "speak text" and always assume that trailing newlines are incidental to the data. Neither receiving nor sending raw data (bytes) is supported, nor is redirecting an external program's output as-is to a file. |
Thank you for that clarification @mikeehsu, I see that now. I've updated my comment to be just a sidenote. |
This becomes an especially difficult problem when piping text to programs cross-platform. For example, running PowerShell (core) on Windows and trying to pipe output to a program running on a Linux server. It simply seems to not be possible at the moment.
Regardless of the input, the pipe here is adding a CRLF which breaks the remote command. |
The addition of the newline appears to be an issue on both the input and output side. On Windows:
If you try the equivalent in cmd.exe: C:\>echo hello there | wsl awk '{print $2,$1}'
there hello What I think happens is that awk returns two strings to stdout and the PowerShell NativeCommandProcessor gets those strings and does a WriteLine() call which inserts the newlines you can see above in hex as 0D0A (CRLF). |
True, on the output side, due to parsing output into an array of lines, PowerShell also does not allow you to distinguish between: # On Unix: NO trailing newline
$out = printf 'hi' and # On Unix: Trailing newline
$out = printf 'hi\n'
Allowing user code to make this distinction would be a nontrivial proposition, given that invocations of external (native) executables don't support any ad-hoc behavioral options, such as via common parameters. Tacking In your # Windows
PS> cmd /c echo there hello | Out-String | Format-Hex
Label: String (System.String) <2C119606>
Offset Bytes Ascii
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
------ ----------------------------------------------- -----
0000000000000000 74 68 65 72 65 20 68 65 6C 6C 6F 0D 0A there hello�� Similarly, on a Unix-like platform, # Unix
PS> "hello there" | awk '{print $2,$1}' | Out-String | Format-Hex
Label: String (System.String) <029F4149>
Offset Bytes Ascii
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
------ ----------------------------------------------- -----
0000000000000000 74 68 65 72 65 20 68 65 6C 6C 6F 0A there hello� As an aside: That your That said, given that a single executable - |
I'm not sure if this adds anything to the conversation, but as a matter of reference: $foo = "foo"
$foon = "foo`n"
@(
'"foo" | xxd'
'("foo" | Format-Hex).HexBytes'
'(Format-Hex -InputObject "foo").HexBytes'
'$foo | xxd'
'($foo | Format-Hex).HexBytes'
'"foo`n" | xxd'
'$foon | xxd'
'($foon | Format-Hex).HexBytes'
) | % {
[PSCustomObject]@{
Command = $_
Output = iex $_
}
} Below results are PS 7.0.3 on Darwin 19.6.0.
This tripped me up a bit even after I thought I knew what was going on. Notably a string ending in a newline still gets a newline appended. I had previously assumed the trailing newline got appended only when missing. |
@petervandivier, good point: a platform-appropriate newline sequence - CRLF on Windows, LF on Unix - is invariably added when a string is sent via the pipeline to a native executable. @SteveL-MSFT, your |
For a specific use case (perhaps one is not needed), this makes setting creating
The secret is created with an additional new line appended making it invalid. |
Is there a workaround so that something like this can encrypt without adding trailing newline characters to the secret text? (I didn't see one in the above discussion.)
|
@spinitron, call via the platform-native shell: # Unix
sh -c 'printf %s ''pa55w0rd'' | gpg -e ...'
# Windows (workaround needed to print a string without a trailing newline)
cmd /c '<NUL set /p ="pa55w0rd" | gpg -e ...' |
Hi again! I was trying to save to a file/capture in variable [expand: terminal]
So i got into the command prompt to make a couple of tests:
And the following is the result. [expand: screenshots of the files opened in HxD]It seems that I tried to understand what it actually generates, by trying a conversion to utf8, but i had no luck:
|
I think this is a separate issue, related to character encoding only:
In other words:
# Once PR #17857 is merged.
[Console]::OutputEncoding.GetBytes("string") | openssl dgst -sha256 -hmac "authcode"
# For better performance use a nested array.
(, [Console]::OutputEncoding.GetBytes("string")) | openssl dgst -sha256 -hmac "authcode" Note: If you use |
I feel pretty strong that this issue should remain open or get another resolution besides auto-close. This is a huge blocker for using If something has changed regarding this behavior, it needs to get cross-linked here. At a bare minimum, this behavior should be formally documented and this issue can get closed as |
Closed "as completed". Is this all just a metric game? At the very least make it |
This is in no way done or completed. It is still an issue as of the latest version of PowerShell. It's a pretty big issue too, primarily on Windows.
|
@PowerShellTeam @SteveL-MSFT Please re-open issue. |
i received like 5-6 emails about issues "closed", this is one like many others.. |
I'm learning cryptography and just want to verify a simple hash from the textbook
I've tried the following commands in PowerShell 7.4.2. None of them produces the correct hash (terminating in '24'). Is there seriously no (non-convoluted) way to accomplish this task other than drop into wsl/git-bash?
Edit: I see it's possible to use raw byte handling now:
|
Steps to reproduce
Run the below command in Linux, Command Prompt, and PowerShell and compare the output.
I also attempted to change the encoding PowerShell was using to UTF-8 but that did not change the value of the returned hash.
Expected behavior
Actual behavior
Environment data
The text was updated successfully, but these errors were encountered: