【问题标题】:PowerShell Start-Job Working DirectoryPowerShell 开始作业工作目录
【发布时间】:2010-02-08 19:42:22
【问题描述】:

有没有办法为 Start-Job 命令指定工作目录?

用例:

我在一个目录中,我想使用 Emacs 打开一个文件进行编辑。如果我直接这样做,它将阻止 PowerShell,直到我关闭 Emacs。但是使用 Start-Job 会尝试从我的主目录运行 Emacs,从而让 Emacs 打开一个新文件而不是我想要的文件。

我尝试使用 $pwd 指定完整路径,但脚本块中的变量直到在 Start-Job 上下文中执行后才会解析。因此,在 shell 上下文中强制解析变量的某种方法也是可以接受的答案。

所以,这是我尝试过的,只是为了完整性:

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

【问题讨论】:

    标签: powershell start-job


    【解决方案1】:

    comments section of some dude's post 提供了很好的解决方案。评论者建议使用Init 参数来设置脚本块的工作目录。

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

    【讨论】:

    • ++ 用于最通用的解决方案:无需帮助脚本,无需后台脚本块需要了解和处理的输入参数。
    • 这应该在 $pwd 周围加上引号来处理路径中的空格
    • @ghostbust555 是正确的,需要单引号,因为这不是变量引用,而是字符串中的变量扩展。
    • @Sander:确实(感谢您的更正 - 我错过了正在构建的 string )。但是,考虑到文件名可能包含 ' 实例,这会中断的可能性很小,因此一个完全可靠的解决方案是:"Set-Location '$($pwd -replace "'", "''")'"
    【解决方案2】:

    一个可能的解决方案是创建一个“踢脚脚本”:

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

    您的脚本将如下所示:

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

    希望这会有所帮助。

    【讨论】:

    • 效果非常好。 -ArgumentList 正是我正在寻找的那种东西。
    • 请记住,这只有在$workingdir 不包含空格或其他特殊字符时才有效。
    • @DiscoInfiltrator:仅传递 $workingdir 在 PowerShell 中可以正常工作,即使是嵌入空格和其他 shell 元字符(您可能正在考虑类似 POSIX 的 shell);验证$dir = 'C:\Program Files\'; function foo() { set-location $args[0] }; foo $dir
    • @Filburt,你为什么叫它“踢脚脚本”?
    • @Bowi 这实际上只是个人命名的事情 - 一个启动另一个脚本或可执行文件的脚本。
    【解决方案3】:

    更新

    PowerShell [Core] 7.0 带来了以下改进

    • 后台作业(以及线程作业和ForEach-Object -Parallel)现在 - 明智地 - 继承调用者的当前(文件系统)位置。

    • 新的-WorkingDirectory 参数允许您明确指定目录。


    总结问题(适用于Windows PowerShellPowerShell Core 6.x

    • Start-Job 开始的后台作业继承当前位置(工作目录)。

      • 在 Windows PowerShell 中默认为 $HOME\Documents,在 PowerShell Core 中默认为 $HOME

      • 如果您使用 PowerShell Core 并且您的目标是 current 目录中的文件,则可以使用以下,因为默认情况下新的... & 语法会在当前目录中运行作业
        emacs RandomFile.txt &

    • 您不能在传递给Start-Job 的脚本块中直接引用来自当前会话的变量。

    补充jdmichal's own helpful answerasavartsov's helpful answer,它们仍然很有效:

    PSv3 引入了一种简单的方法,通过$using: 在不同上下文(作为后台作业或在远程机器上)执行的脚本块中引用 当前 会话的变量值范围:

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

    或者:

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

    about_Remote_Variables


    注意:

    • This GitHub issue 报告了令人惊讶的无法在传递给-InitializationScript 的脚本块中使用$using:,即使它在主脚本块中工作(隐含的-ScriptBlock 参数)。
      • Start-Job -Init { Set-Location $using:PWD } { emacs RandomFile.txt } # FAILS

    【讨论】:

      【解决方案4】:

      试试这个

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

      这里$input 是预定义变量,内部采用-inputobject 参数的值

      【讨论】:

        【解决方案5】:

        Start-Job 对你需要的东西来说太过分了(在后台运行命令)。请改用 Start-Process

        Start-Process -NoNewWindow emacs RandomFile.txt
        

        在这种方法中当前目录没有问题。我还创建了一个函数来使其尽可能简单:

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

        然后调用变为:

        bg emacs RandomFile.txt
        

        这适用于 Windows 7 (Powershell v2)。

        【讨论】:

        • 但是终端关闭后Start-Process仍然存在?
        【解决方案6】:

        为了完整起见,这是我根据 Filburt 的回答实现的最终脚本,社区维基风格:

        function Start-Emacs ( [string]$file )
        {
            Start-Job -ArgumentList "$pwd\$file" { emacs $args[0] }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2018-11-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多