现在,我正在编写一个 Groovy 脚本来调用其他接口。但是我需要在运行脚本时更改我当前的工作路径。我知道这在 Java 中是不可能的。在 Groovy 中可以吗?
4 回答
如果您可以将其他脚本作为单独的进程运行,则可以提供 ProcessBuilder 参数工作目录:
def processBuilder=new ProcessBuilder(command)
processBuilder.directory(new File("Working dir"))
def process = processBuilder.start()
或者
command.execute(null, new File("Working dir"))
这样该过程将切换到您的新文件夹并在那里执行。
据我所知,Java/groovy 并没有真正“拥有”工作目录。启动 groovy 的 shell 有一个和任何子“命令”直接从该 shell 继承。
Java 似乎也读取了 shell 的当前目录并将其存储在“user.dir”中。这用作“文件”对象的基础,因此如果您使用 System.setProperty("user.dir", "c:/windows") 它将更改未来对 new File(".") 的调用,但不会更改父 shell 目录(因此不是子目录)。
以下是三种可能适用于不同场景的“变通办法”:
1)我有点克服了这个非常具体的任务......我想将“cd”实现为一个groovy脚本。这只是可能的,因为我所有的脚本都已经被“包装”在一个批处理文件中。我这样做是为了让我的脚本可以创建一个名为“afterburner.cmd”的文件,如果它存在,它将在脚本退出时执行。有一些批处理文件技巧可以使这项工作。
启动 cmd 文件还可以在调用 groovy 脚本/应用程序之前“设置”当前目录。
顺便说一句,拥有一个启动 cmd 比我想象的要有用得多——它使您的环境保持不变,并允许您更轻松地将“脚本”部署到其他机器上。我什至让我的脚本编译为 .classes,因为结果证明将 .groovy 编译为 .class 并使用“Java”启动 .class 比仅使用“groovy”运行脚本要快——而且通常你可以跳过编译步骤,这使它更快!
2)对于一些小命令,你可以写一个这样的方法:
def currentDir = "C:\\"
def exec(command, dir = null) {
"cmd /c cd /d ${dir?:currentDir} && $command".execute().text
}
// Default dir is currentDir
assert exec("dir").endsWith("C:\\>")
// different dir for this command only
assert exec("dir", "c:\\users").endsWith("C:\\users")
// Change default dir
currentDir = "C:\\windows"
assert exec("dir").endsWith("C:\\windows")
如果不需要“cmd”,它将比“”.execute() 慢。
3)编写一个维护“打开”命令外壳的小类(我做过一次,有点复杂),但想法是:
def process="cmd".execute()
def in=process.in
def out=process.out
def err=process.err
现在“in”是一个输入流,您可以从中分离/读取,“out”是一个输出流,您可以向其中写入命令,密切关注“err”以检测错误。
该类应将命令写入输出,读取输入直到命令完成,然后将输出返回给用户。
问题是检测任何给定命令的输出何时完成。通常,您可以检测到“C:...”提示并假设这意味着命令已完成执行。您也可以使用超时。两者都很容易犯错。您可以将该 shell 的提示设置为独特的东西,以使其不易出错。
优点是这个 shell 可以在您的应用程序的整个生命周期内保持打开状态,并且可以显着提高速度,因为您不会重复创建“cmd”shell。如果您创建一个包装 Process 对象的类(我们称之为“CommandShell”),那么它应该非常易于使用:
def cmd=new CommandShell()
println cmd.execute("cd /d c:\\")
println cmd.execute("dir") // Will be the dir of c:\
我曾经写过一个像这样的 groovy 类,它需要大量的试验,你的实例可能会被“exit”之类的命令破坏,但这是可能的。
您可以将其包装在 dir 块中。例如:
dir('yourdirectory') {
codeblock
}