Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way to return values from a function that writes to STDOUT

I have some helper functions that write to STDOUT for logging purposes. Some of these functions return a value to the caller, but the entire output from the function is returned.

How can I have my functions write to STDOUT and return a value to the caller without the return value being polluted with all the STDOUT emitted during the function call?

I'm looking for some kind of design pattern or best practise.

Consider this script:

Function a
{
    Write-Output "In Function a"
    $a = 4
    return $a   
}

$b = a

Write-Output "Outside function: `$b is $b"

The output is

Outside function: $b is In Function a 4

But I want the output to be:

In Function a
$b is 4
like image 634
Mark Allison Avatar asked Jan 20 '14 10:01

Mark Allison


People also ask

How do you get the value returned from a function?

To return a value from a function, you must include a return statement, followed by the value to be returned, before the function's end statement. If you do not include a return statement or if you do not specify a value after the keyword return, the value returned by the function is unpredictable.

How do you return a value from a function in PowerShell?

If you are inside of a function and return a value with the return keyword, the function will return that value and exit the function. The return keyword causes the function to exit after outputting the first process. PowerShell will then generate output for both processes.

Can a PowerShell script return a value?

The return keyword exits a function, script, or script block. It can be used to exit a scope at a specific point, to return a value, or to indicate that the end of the scope has been reached.

Which statement is used by a function use to return a value?

A return statement ends the execution of a function, and returns control to the calling function. Execution resumes in the calling function at the point immediately following the call. A return statement can return a value to the calling function.


2 Answers

In PowerShell all non-captured output inside a function is returned, not just the argument of return. From the documentation:

In PowerShell, the results of each statement are returned as output, even without a statement that contains the return keyword.

It doesn't matter if the function looks like this:

function Foo {
  'foo'
}

or like this:

function Foo {
  'foo'
  return
}

or like this:

function Foo {
  return 'foo'
}

it will return the string foo either way.

To prevent output from being returned, you can

  • write to the host or one of the other ouptput streams (depending on the type of output you want to create):

    Function a {
      Write-Host 'some text'
      Write-Verbose 'verbose message'
      Write-Information 'info message'   # requires PowerShell v5 or newer
      $a = 4
      return $a
    }
    

    Side note: Write-Information is not available prior to PowerShell v5 when the information stream was introduced, and starting with that version Write-Host also writes to that stream rather than directly to the host console.

  • capture the output in a variable or "assign" it to $null:

    Function a {
      $var = Write-Output 'some text'
      $null = Write-Output 'some text'
      $a = 4
      return $a
    }
    
  • or redirect the output to $null:

    Function a {
      Write-Output 'some text' | Out-Null
      Write-Output 'some text' >$null
      $a = 4
      return $a
    }
    
like image 65
Ansgar Wiechers Avatar answered Oct 21 '22 11:10

Ansgar Wiechers


another approach:

  1. in your function, do logging via Write-Information.
  2. in the calling scope, call the function inside a sub-expression and redirect the information stream of the sub-expression to stdout. Be sure to assign the return value of the function to a variable, or it will also go to stdout.

eg

function bar() {
  Write-Information "Hello from bar()"
  return 4
}

$($x = bar) 6>&1

Write-Output "in main `$x = $x"

If you're on an old version of powershell and can't use Write-Information the same approach works with Write-Verbose. In that case you'd redirect as 4>&1. With verbose you'll get the ugly yellow/black and "VERBOSE" text, unless you're redirecting the stdout of the overall script into a file, in which case the VERBOSE: tag will be omitted.

like image 23
orion elenzil Avatar answered Oct 21 '22 12:10

orion elenzil