Question

Is there a way to specify a working directory to the Start-Job command?

Use-case:

I'm in a directory, and I want to open a file using Emacs for editing. If I do this directly, it will block PowerShell until I close Emacs. But using Start-Job attempts to run Emacs from my home directory, thus having Emacs open a new file instead of the one I wanted.

I tried to specify the full path using $pwd, but variables in the script block are not resolved until they're executing in the Start-Job context. So some way to force resolving the variables in the shell context would also be an acceptable answer to this.

So, here's what I've tried, just for completeness:

Start-Job { emacs RandomFile.txt }
Start-Job { emacs "$pwd/RandomFile.txt" }
Was it helpful?

Solution

A possible solution would be to create a "kicker-script":

Start-Job -filepath .\emacs.ps1 -ArgumentList $workingdir, "RandomFile.txt"

Your script would look like this:

Set-Location $args[0]
emacs $args[1]

Hope this helps.

OTHER TIPS

There is nice solution from comments section of some dude's post. Commenter suggests to use Init parameter to setup working directory of script block.

function start-jobhere([scriptblock]$block) {
    Start-Job -Init ([ScriptBlock]::Create("Set-Location '$pwd'")) -Script $block
}

To summarize the problem:

  • A background job started with Start-Job does not inherit the current location (working directory).

    • It defaults to $HOME\Documents in Windows PowerShell, and $HOME in PowerShell Core (as of PSv5.1 / PSv6 alpha).

    • If you're using PowerShell Core and you're targeting a file in the current directory, you can use the following, because the new ... & syntax by default runs the job in the current directory:
      emacs RandomFile.txt &

  • You cannot directly reference variables from the current session in a script block passed to Start-Job.

To complement jdmichal's own helpful answer and asavartsov's helpful answer, which still work well:

PSv3 introduced a simple way to reference the current session's variables in a script block that is executed in a different context (as a background job or on a remote machine), via the $using: scope:

Start-Job { Set-Location $using:PWD; emacs RandomFile.txt }

Alternatively:

Start-Job { emacs $using:PWD/RandomFile.txt }

Note:

  • This GitHub issue proposes adding a -WorkingDirectory to the Start-Job cmdlet.

    • Start-Job -WorkingDirectory $PWD { emacs RandomFile.txt } # WISHFUL THINKING
  • This GitHub issue reports the surprising inability to use $using: in the script block passed to -InitializationScript, even though it works in the main script block (the implied -ScriptBlock parameter).

    • Start-Job -Init { Set-Location $using:PWD } { emacs RandomFile.txt } # FAILS

try this

Start-Job -inputobject $pwd -scriptblock { emacs "$input/RandomFile.txt" }

Here $input is predefined variable that internally take the value of -inputobject parameter

Start-Job is an overkill for what you need (running a command in the background). Use Start-Process instead:

Start-Process -NoNewWindow emacs RandomFile.txt

There are no issue with the current directory in this approach. I have also created a function to make this as simple as possible:

function bg() {Start-Process -NoNewWindow @args}

and then the invocation becomes:

bg emacs RandomFile.txt

This works on Windows 7 (Powershell v2).

Just for completeness, here's the final script I implemented based on Filburt's answer, community-wiki style:

function Start-Emacs ( [string]$file )
{
    Start-Job -ArgumentList "$pwd\$file" { emacs $args[0] }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top