问题
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" }
回答1:
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.
回答2:
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
}
回答3:
Update:
PowerShell [Core] 7.0 brings the following improvements:
Background jobs (as well as thread jobs and
ForEach-Object -Parallel
) now - sensibly - inherit the caller's current (filesystem) location.A new
-WorkingDirectory
parameter allows you to specify a location explicitly.
To summarize the problem (applies to Windows PowerShell and PowerShell Core 6.x)
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.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 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
回答4:
try this
Start-Job -inputobject $pwd -scriptblock { emacs "$input/RandomFile.txt" }
Here $input
is predefined variable that internally take the value of -inputobject
parameter
回答5:
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).
回答6:
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] }
}
来源:https://stackoverflow.com/questions/2224350/powershell-start-job-working-directory