1

Simple question, I want to run docker command in background.
(Actually running any command with command line parameters under Powershell is my real question, but docker is a simple concrete one)

I have a command

docker run -ti --rm -e DISPLAY=$DISPLAY firefox

which runs fine under Powershell, but it blocks.

I want to runs the equivalent method of doing "&" as under *nix:

docker run -ti --rm -e DISPLAY=$DISPLAY firefox &

I've tried

but neither works for me:

> ping google.com &
At line:1 char:17
+ ping google.com &
+                 ~
The ampersand (&) character is not allowed.

> Start-Process "C:\Program Files\Docker\Docker\resources\bin\docker.exe" run -ti --rm -e DISPLAY=$DISPLAY firefox
Start-Process : Parameter cannot be processed because the parameter name 'e' is ambiguous. Possible
matches include: -ErrorAction -ErrorVariable.
At line:1 char:86
+ ... Files\Docker\Docker\resources\bin\docker.exe" run -ti --rm -e DISPLAY ...
+                                                                ~~
    + CategoryInfo          : InvalidArgument: (:) [Start-Process], ParameterBindingException
    + FullyQualifiedErrorId : AmbiguousParameter,Microsoft.PowerShell.Commands.StartProcessCommand

Tried to wrap the whole command within Start-Process { ... } doesn't work either.

[UPDATE/Summary]

The accepted answers works (after I removed "-ti" from the command line), as @nischay goyal has put, "please don't use -it as it opens the terminal and blocks it.". The error I got was:

the input device is not a TTY.  If you are using mintty, try prefixing the command with 'winpty'
    + CategoryInfo          : NotSpecified: (the input devic...d with 'winpty':String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError
    + PSComputerName        : localhost
  • So Start-Job might not fit as a general purpose way of doing "&", e.g., if I want to start bash & that way.

  • However, the Start-Process works after passing all the rest of docker command line parameters to the -ArgumentList parameter as a single string.

  • And of course, like all docker/Linux camp people say, use -d.

All in all, there are many ways to solve the problem. Pick the one that suits you.

mklement0
  • 382,024
  • 64
  • 607
  • 775
xpt
  • 20,363
  • 37
  • 127
  • 216

4 Answers4

1

The firefox command isn't expecting any input on stdin, and doesn't need a tty. So remove the -it. Next add -d which stands for detached mode, the standard way to run daemons inside of docker, or other non-interactive commands.

docker run -d --rm -e DISPLAY=$DISPLAY firefox
BMitch
  • 231,797
  • 42
  • 475
  • 450
  • 1
    Thanks, however, note that this is a question more on Powershell than on docker. I.e., running any command with command line parameters under Powershell is my real question. – xpt Mar 29 '20 at 22:37
1

To run the docker container in detached mode, please don't use -it as it opens the terminal and blocks it.

docker run --rm -e DISPLAY=$DISPLAY firefox

For running the command in background in PowerShell, As long as the command is an executable or a file that has an associated executable, use Start-Process (available from v2):

Start-Process -NoNewWindow ping google.com
nischay goyal
  • 3,206
  • 12
  • 23
1

Use Start-Job to run a command in the background in PowerShell.

In PowerShell [Core] 6+, you can also place & at the end of your command, the same way you can in POSIX-like shells such as Bash.

In both cases, a job object (System.Management.Automation.PSRemotingJob) is returned that you can manage with the various *-Job cmdlets - see about_Jobs.

Jobs in PowerShell are similar to jobs in POSIX-like shells (such as Bash), but there are some fundamental differences, notably the inability run interactive commands in the background - see this comment on GitHub.

Background jobs use a child process that runs a hidden PowerShell instance in the background, which is slow and resource-intensive.

Therefore consider the thread-based Start-ThreadJob cmdlet as a faster and more light-weight alternative - see this answer.

Syntax that works in PowerShell versions below 6 too, with Start-Job:

# Preferable alternative: Start-ThreadJob
$job = Start-Job { docker run --rm -e DISPLAY=$using:DISPLAY firefox }

Note: -ti was removed, because, as Nischay Goyal points out, it would open an interactive shell session, which means that the call wouldn't return until that session is manually closed. However, not that Start-Job generally doesn't support running interactive programs in the background, as explained here.

Note the need to refer to the $DISPLAY variable in the caller's scope via the $using: scope specifier - see about_Remote_Variables.

Caveat: In PowerShell versions up to 6.x, background jobs started this way used a fixed working directory unrelated to the caller's - see this answer.

PowerShell [Core] 6+ alternative: placing & at the end of a command:

$job = docker run --rm -e DISPLAY=$DISPLAY firefox &

Note that you do not need the $using: scope specifier with this syntax, and even in PowerShell 6.x the job sees the same working directory as the caller.

Note that there's no similarly concise syntax for creating thread jobs (the equivalent of a Start-ThreadJob call) yet as of PowerShell 7.0, but adding one is the subject of this feature request on GitHub.


As stated, you can use the various other *-Job cmdlets to manage a job once created (they also manage thread jobs created with Start-ThreadJob); for instance, the following command synchronously waits for the job to complete, prints its output, and then removes the job.

$job | Receive-Job -Wait -AutoRemoveJob

As for what you tried:

The postpositional & in ping google.com & didn't work, because you're running on Windows PowerShell (PowerShell versions up to v5.1), whereas this syntax requires PowerShell [Core] version 6 or higher.

Start-Process is designed to launch an executable asynchronously, and in a new window by default (on Windows).
It is primarily useful for launching GUI applications (asynchronously) or running shell commands in a new console window.

While it can also launch processes invisibly, you get little control over that process, and its output can only be captured indirectly, via text files.

The reason your invocation failed is that you tried to pass the pass-through arguments directly to Start-Process, instead of passing them to the -ArgumentList parameter (as a single string, in the simplest case).

mklement0
  • 382,024
  • 64
  • 607
  • 775
0

to fully execute a command in docker with docker in background, you can use:

docker run $YourOption $ImageDocker exec $yourCommand 

and don't use -i -t options, it opens terminal

do something like

docker run --rm -e DISPLAY=$DISPLAY firefox exec "ping google.com"