Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the equivalent of xargs in PowerShell?

The POSIX-defined xargs command takes all of the items it receives from standard input and passes them as command-line arguments to the command it receives on it's own command line. E.g: grep -rn "String" | xargs rm.

What's the equivalent in PowerShell?

The following questions all ask this:

  • Convert xargs Bash command to PowerShell?
  • What is the PowerShell equivalent to this Bash command?

but there is no correct answer because all the answers either use ForEach-Object, which will process items one-at-a-time (like xargs -n1) which gets the desired result for the examples given, or store the intermediate result in a variable, which offends my functional commandline-fu.

like image 315
simonwo Avatar asked Apr 05 '16 14:04

simonwo


People also ask

What is xargs in shell script?

xargs (short for "eXtended ARGumentS") is a command on Unix and most Unix-like operating systems used to build and execute commands from standard input. It converts input from standard input into arguments to a command.

What does $_ mean in PowerShell?

The “$_” is said to be the pipeline variable in PowerShell. The “$_” variable is an alias to PowerShell's automatic variable named “$PSItem“. It has multiple use cases such as filtering an item or referring to any specific object.

What is xargs option?

xargs reads items from the standard input, delimited by blanks (which can be protected with double or single quotes or a backslash) or newlines, and executes the command (default is echo) one or more times with any initial-arguments followed by items read from standard input.


2 Answers

There are two ways that I've found. The first is probably more idiomatic PowerShell, and the second is more true to the pipe-based spirit of xargs.

As an example, let's say we want to pass all our cat pics to myapp.exe.

Method #1: Command substitution

You can do something similar to using $(command substitution) in sh by embedding your pipeline in the command string:

&"myapp.exe" @(Get-ChildItem -Recurse -Filter *.jpg | Another-Step) 

The @(...) creates an array from the command inside it, and PowerShell automatically expands arrays passed to & into seperate command-line parameters.

However, this does not really answer the question, because it will only work if you have control over the command you want to pass to, which may not be the case.

Method #2: True piping

You can also construct a "double pipeline" by having a sub-expression to pipe your objects, collecting them to an array, and then piping the array to your final command.

,@(Get-ChildItem -Recurse -Filter *.jpg | Another-Step) | %{&"myapp.exe" $_} 

The @(...) as before collects the items into an array, and the array is then piped to the final command which is invoked using % (ForEach-Object). Ordinarily, this would then loop over each item individually, because PowerShell will automatically flatten the array when it's piped, but this can be avoided by prepending the , operator. The $_ special variable is then used as normal to embed the passed array.

So the key is to wrap the pipeline you want to collect in ,@(...), and then pipe that to something in %{...}.

like image 175
simonwo Avatar answered Oct 19 '22 23:10

simonwo


I've been using this filter for the basic xargs execution.

filter xargs { ($h,$t) = $args; & $h ($t + $_) } 

which is roughly equivalent to:

filter xargs { & $args[0] ($args[1..$args.length] + $_) } 

Examples

 docker ps -q | xargs docker stop   gem list | % { $_.split()[0] } | xargs gem uninstall -aIx 
like image 38
Ian Davis Avatar answered Oct 19 '22 22:10

Ian Davis