为什么在将参数插入双引号字符串时,Groovy的.equals()在jenkins管道脚本中失败?

问题描述 投票:0回答:2

(注意:我已经查看了类似的问题(例如this,其中问题是无法修改shell命令的输出)但我认为这种情况是截然不同的。)

我在Groovy中有一个使用参数的管道脚本(通过properties([parameters([...)。当我将参数的值插入到双引号字符串中时,它无法对两个捕获的.equals()检查(我的意思是“捕获和.trim()d!”)stdout(这是我的用例)甚至是简单的字符串字面量。

我可以使用.trim()来解决这个问题,(尽管你可以看到,通过我回应它们并检查.length(),没有任何东西给.trim()),但我怀疑只有“有效”,因为它做了隐含的.toString()--这也是一个成功的解决方法。

对我来说这看起来像个错误,但它确实是我第一次使用Groovy,所以也许我错过了一些东西 - 任何人都可以解释一下吗?

即使是一个简单的文字"foo" failes(即"foo".equals("${params.foo_the_parameter}")。插值参数是其他类型的对象还是什么?

[编辑在得到@Matias Bjarland的答案后,我修改了下面的代码,使用println而不是带壳的回声,因为它使输出更简洁。他建议的解决方案反映在评论栏中。]

我的常规代码:

node() {
    properties([
        parameters([
            string(
                defaultValue: 'foo',
                description: 'This is foo',
                name: 'foo_the_parameter'
            )
        ])
    ])

    /* this is what I learned from the accepted answer
    bob="${params.foo_the_parameter}"
    println("class of interpolated param is ${bob.class}")
    simple_foo="foo"
    println("class of \"foo\" is ${simple_foo.class}")
    */
    echoed_foo = sh(script:"echo 'foo'", returnStdout: true).trim()
    println "echoed foo is [$echoed_foo], params foo is [${params.foo_the_parameter}]";
    echo_foo_length = echoed_foo.length()
    dqs_foo_length = "${params.foo_the_parameter}".length()
    println "their lengths are: echo: [$echo_foo_length] and dqs: [$dqs_foo_length]";
    if (echoed_foo.equals("${params.foo_the_parameter}")) {
        println "SUCCESS they are equals()"
    }
    else {
        println "FAIL they are not equals()" //this one fires
    }
    if (echoed_foo.equals("${params.foo_the_parameter}".trim())) {
        println "SUCCESS they are equals() after the dqs gets a trim()" //this one fires
    }
    else {
        println "FAIL they are not equals()after the dqs gets a trim()"
    }
    if (echoed_foo.equals("${params.foo_the_parameter}".toString())) {
        println "SUCCESS they are equals() after the dqs gets a toString()" //this one fires
    }
    else {
        println "FAIL they are not equals()after the dqs gets a toString()"
    }

    if ("foo".equals("${params.foo_the_parameter}")) {
        println "SUCCESS at least a simple literal \"foo\" works"
    }
    else {
        println "FAIL even a simple literal \"foo\" fails to be .equals() with the interpolated parameter" //this one fires
    }
}

詹金斯输出:

Started by user Michael South
[Office365connector] No webhooks to notify
Obtained jenkins.groovy from git [email protected]:msouth/test_groovy_equals.git
Running in Durability level: MAX_SURVIVABILITY
[Pipeline] node
Running on subnet_mon_02 in /opt/jenkins/m1/workspace/field-analytics-org/test_string_equals
[Pipeline] {
[Pipeline] properties
[Pipeline] sh
[test_string_equals] Running shell script
+ echo foo
[Pipeline] echo
echoed foo is [foo], params foo is [foo]
[Pipeline] echo
their lengths are: echo: [3] and dqs: [3]
[Pipeline] echo
FAIL they are not equals()
[Pipeline] echo
SUCCESS they are equals() after the dqs gets a trim()
[Pipeline] echo
SUCCESS they are equals() after the dqs gets a toString()
[Pipeline] echo
FAIL even a simple literal "foo" fails to be .equals() with the interpolated parameter
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
[Office365connector] No webhooks to notify
Finished: SUCCESS
groovy jenkins-pipeline
2个回答
1
投票

不确定这是否是你要击中的,但请考虑以下groovy代码:

def x = 'World'
def gstr = "Hello ${x}!"
def str  = 'Hello World!'

println "class of gstr: ${gstr.class}"
println "class of str:  ${str.class}"

println(gstr.equals(str))
println(gstr.toString().equals(str))

哪,运行时打印:

~> groovy solution.groovy
class of gstr: class org.codehaus.groovy.runtime.GStringImpl
class of str:  class java.lang.String
false
true

~> 

换句话说,字符串插值将导致groovy GString的实例,其不一定等于具有相同内容的字符串。使用.toString()强制评估解决了这个特殊问题。

引用groovy documentation on string interpolation

除了单引号和三引号字符串之外,任何Groovy表达式都可以在所有字符串文字中进行插值。插值是在对字符串求值时将字符串中的占位符替换为其值的行为。占位符表达式由$ {}包围,或者以$表示前缀。当GString被传递给以String为参数的方法时,通过调用该表达式上的toString(),将占位符内的表达式值计算为其字符串表示形式。

换句话说,您必须使用以下变体将GString实例分配给计划java String:

String str1 = gstr
def str2 = gstr as String
def str3 = (String) gstr

,调用一个接受String的方法(将GString强制转换为字符串)或调用gstr.toString()强制转换。

希望有所帮助。


2
投票

In Groovy, you can simply use == to compare strings

在Java中,您使用String.equals(),因为str1 == str2没有达到您的期望:Java比较引用而不是值。

在Groovy中,你可以写str1 == str2,它可以做你期望它做的事情。 Groovy使用String.compareTo()比较值,并在结果为true时返回0

GString g = "${'foo'}"
String s = "foo"

assert g == "foo" && s == "foo"
assert g instanceof GString && s instanceof String
assert !s.equals(g) && !g.equals(s)
assert g.compareTo(s) == 0 && s.compareTo(g) == 0
assert g == s && s == g 
© www.soinside.com 2019 - 2024. All rights reserved.