Groovy脚本文件名中的禁止字符?

4
3个回答

6
最准确的答案是使用与Java类相同的命名标准来命名Groovy脚本。Groovy和Java一样支持Unicode字符编码,您很可能可以使用任何Unicode字符作为脚本名称(这并不意味着您应该这样做)。
每个Groovy脚本都被编译为一个扩展groovy.lang.Script类的Java类。它的名称取自Groovy脚本文件名。看一个例子:someSimpleGroovyScript.groovy
println "test"

当我们使用groovyc someSimpleGroovyScript.groovy编译它时,我们会看到一个名为someSimpleGroovyScript.class的类文件。现在让我们看看这个类是什么样子的:

javap someSimpleGroovyScript

我们将得到类似以下的内容:
Compiled from "someSimpleGroovyScript.groovy"
public class someSimpleGroovyScript extends groovy.lang.Script {
  public static transient boolean __$stMC;
  public someSimpleGroovyScript();
  public someSimpleGroovyScript(groovy.lang.Binding);
  public static void main(java.lang.String...);
  public java.lang.Object run();
  protected groovy.lang.MetaClass $getStaticMetaClass();
}

Groovy脚本名称的边缘案例

尽管Java类命名标准适用于Groovy脚本名称,但有一些边缘情况Groovy支持。

在脚本名称中使用-字符

您可以将脚本命名为a-b.groovy并作为Groovy脚本运行:

groovy a-b.groovy

你甚至可以使用groovyc编译它,得到以下的Java类:

Compiled from "a-b.groovy"
public class a-b extends groovy.lang.Script {
  public static transient boolean __$stMC;
  public a-b();
  public a-b(groovy.lang.Binding);
  public static void main(java.lang.String...);
  public java.lang.Object run();
  protected groovy.lang.MetaClass $getStaticMetaClass();
}

尽管这个类名对于Java编译器来说不正确,但你仍然可以使用Java运行它(你需要将groovy-all添加到类路径中):

java -classpath ".:./groovy-all-2.4.12.jar" a-b

在脚本名称中使用 $

Groovy 中你甚至可以将你的脚本命名为 123$.groovy,然后直接运行它:

groovy 123\$.groovy

然而,Groovy编译器在将此脚本编译为Java类时会将$替换为下划线:

javap 123_

输出:

Compiled from "123$.groovy"
public class 123_ extends groovy.lang.Script {
  public static transient boolean __$stMC;
  public 123_();
  public 123_(groovy.lang.Binding);
  public static void main(java.lang.String...);
  public java.lang.Object run();
  protected groovy.lang.MetaClass $getStaticMetaClass();
}

您仍然可以使用Java运行这样编译的脚本:

java -classpath ".:./groovy-all-2.4.12.jar" 123_

使用脚本名称中的空格

您也可以在脚本名称中使用空格,例如this is script.groovy 可以执行以下命令:

groovy this\ is\ script.groovy

Groovy编译器将用下划线替换每个空格:

Compiled from "this is script.groovy"
public class this_is_script extends groovy.lang.Script {
  public static transient boolean __$stMC;
  public this_is_script();
  public this_is_script(groovy.lang.Binding);
  public static void main(java.lang.String...);
  public java.lang.Object run();
  protected groovy.lang.MetaClass $getStaticMetaClass();
}

您仍然可以使用Java运行这样编译过的脚本:
java -classpath ".:./groovy-all-2.4.12.jar" this_is_script

使用class.groovy作为脚本名称

更进一步,您可以创建一个名为class.groovy的脚本,它将编译成以下Java类:

Compiled from "class.groovy"
public class class extends groovy.lang.Script {
  public static transient boolean __$stMC;
  public class();
  public class(groovy.lang.Binding);
  public static void main(java.lang.String...);
  public java.lang.Object run();
  protected groovy.lang.MetaClass $getStaticMetaClass();
}

javac编译器不允许您编译具有此名称的类,但是java在运行此字节码时没有任何问题:

java -classpath ".:./groovy-all-2.4.12.jar" class

最后一位是否真的应该是引号? - cfrick
1
@cfrick 是的,你说得对。我喜欢这种格式,但我们只把引用放在 blockquote 中。感谢你的反馈。 - Szymon Stepniak

3
由于脚本文件名用于生成相应的类名,因此它将受到有效Java类名称的限制。 Java类名中的有效字符 引用:
您几乎可以使用任何字符,包括大多数Unicode字符!精确定义在Java语言规范第3.8节标识符中
标识符是Java字母和Java数字无限长度序列,第一个必须是Java字母......字母和数字可以来自整个Unicode字符集......这允许程序员在使用其母语编写的程序中使用标识符。
标识符不能与关键字(§3.9)、布尔文字(§3.10.3)或null文字(§3.10.7)具有相同的拼写(Unicode字符序列),否则会导致编译时错误。

这个链接中最受欢迎的答案说“几乎任何字符,包括大多数Unicode字符”,你可以认为“几乎”不是对“哪些字符是非法的完整列表”的理想回答 :-/ - Nicolas Raoul
我主要是指从Java语言规范中复制的黄色块,但无论如何上面的答案更好。 - Michael Rutherfurd
哦,这就是发布链接的问题之一,很难知道实际指的是什么。您介意复制/粘贴相关部分,这样即使那个问题被编辑或答案改变,您的回答仍然有效吗?非常感谢! - Nicolas Raoul

1

我遇到了一个奇怪的问题,这个脚本包含一个带有破折号的文件名和一个函数,该函数将 Closure 作为参数。

让我们考虑这个例子,test-script.groovy

#!/usr/bin/env groovy

void foo(String msg, Closure clo)
{
    println msg
    clo()
}

foo 'bar', { -> println 'closure-bar'}

在我的开发环境中,使用 Groovy 2.4.16 它能够完美运行,它会输出:

bar
closure-bar

在生产环境中,使用Groovy 2.4.5版本时,我遇到了以下错误:
Caught: java.lang.ClassFormatError: Illegal class name "test-script$foo" in class file test-script$foo
java.lang.ClassFormatError: Illegal class name "test-script$foo" in class file test-script$foo
        at test-script.run(test-script.groovy:9)

如果我将test-script.groovy重命名为testScript.groovy,它可以在2.4.16和2.4.5版本中工作。

我追踪到这个"错误修复"是在Groovy 2.4.15版本中修复的。在此版本之前,它无法正常工作。

这个版本的changelog没有显示任何相关的修复,所以可能已经被包含在其他的错误修复中了。

无论如何,我已经卡了几个小时在这个问题上,如果能帮助到其他人,那就太好了!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接