Home > Mobile >  Keep newlines and tabs in argument to program - Powershell
Keep newlines and tabs in argument to program - Powershell

Time:03-31

I'm using Powershell to make a call to a program that prints a Python config file that's structured like this:

[distutils]
index-servers =
    some-pypi

[some-pypi]
repository: https://path/to/pypi

What I'm trying to do is pass the entirety of that output as a string to another command. What keeps on happening is that any time I go to pass it to the program that consumes it, Powershell ends up taking out all the newline and tab special characters. This creates buggy output.

Here are some relevant commands and their outputs.

> command to print config

Which prints everything with the newline and tab characters intact.

> $settings = command to print config
> echo $settings

Which, when echoed, prints everything with the newline and tab characters intact.

> consuming-program $settings

This fails to parse as the expression resolves providing all that output as multiple arguments to the program instead of a single argument.

> consuming-program "$settings"

This takes out all of the newline and tab characters.

> consuming-program "$(command to print config)"

Also takes out all the newline characters.

What am I missing? How can I retain the original output and feed it into my program as a single argument with the special characters intact??

CodePudding user response:

This is happening because the output from the command is captured as an array of strings rather than a single string.

For example if we use this command as our baseline:

C:\> dotnet

Usage: dotnet [options]
Usage: dotnet [path-to-application]

Options:
  -h|--help         Display help.
  --info            Display .NET information.
  --list-sdks       Display the installed SDKs.
  --list-runtimes   Display the installed runtimes.

path-to-application:
  The path to an application .dll file to execute.

and then capture the output in PowerShell we can see it's an array of strings - one per line of output - rather than a single multi-line string:

PS> $x = dotnet
PS> $x.GetType().FullName
System.Object[]

When you output $x to the console it shows each item in the array on a separate line so it appears visually to be the same as the console output:

PS> $x

Usage: dotnet [options]
Usage: dotnet [path-to-application]

Options:
  -h|--help         Display help.
  --info            Display .NET information.
  --list-sdks       Display the installed SDKs.
  --list-runtimes   Display the installed runtimes.

path-to-application:
  The path to an application .dll file to execute.

but when you use it as command argument something else is happening - it's being serialised to a single string by joining the items in the array with a single space as a separator:

 Usage: dotnet [options] Usage: dotnet [path-to-application]  Options:   -h|--help         Display help.   --info            Display .NET information.   --list-sdks       Display the installed SDKs.   --list-runtimes   Display the installed runtimes.  path-to-application:   The path to an application .dll file to execute.

This is basically just how PowerShell serialises arrays in some scenarios. For example, compare the output from these two commands:

PS> @( "aaa", "bbb", "ccc" )
aaa
bbb
ccc

PS> write-host @( "aaa", "bbb", "ccc" )
aaa bbb ccc

One fix, as suggested by @iRon in the comments, is to serialise the string yourself before using it in your command:

PS> $y = $x | Out-String
PS> $y

And then you can use $y as your command argument with the original formatting preserved.

  • Related