We need to get the value of dynamically constructed variables.
What I mean is we have a variable loaded from a property file called data8967677878788node. So when we run echo $data8967677878788node we get the output test.
Now in data8967677878788node the number part 8967677878788 needs to be dynamic. That means there could be variables like
data1234node
data346346367node
and such.
The number is an input argument to the script. So we need something like this to work
TESTVAR="data`echo $DATANUMBER`node"
echo $$TESTVAR #This line gives the value "test"
Any idea on how this can be accomplished
You can use BASH's indirect variable expansion:
data346346367node='test'
myfunc() {
datanumber="$1"
var1="data${datanumber}node"
echo "${!var1}"
}
And call it as:
myfunc 346346367
Output:
test
Your code is actually already pretty close to working, it just needs to be modified slightly:
TESTVAR="data`echo $DATANUMBER`node"
echo ${!TESTVAR}
If $DATANUMBER has the value 12345 and $data12345node has the value test then the above snippet will output test.
Source: http://wiki.bash-hackers.org/syntax/pe#indirection
Related
I have a pipeline parameter fed by a config file in SQL.
Sometimes that parameter will be empty, not NULL but just empty ('').
How do I write an expression that will evaluate the parameter to TRUE/FALSE(blank/not blank) that I can put into my IF activity?
Basic question but thanks a lot.
I tried
#pipeline().parameters.x = ''
but it just told me Parameter x = '' was not found .......
You can use the below expression in the if activity to evaluate a parameter is empty or not.
#empty(pipeline().parameters.ok)
Sample demonstration:
A sample parameter ok.
For example, purpose I have created a string variable which I will use inside if to check the output.
In if give the above expression.
Inside True activities I have given a set variable activity and gave some value and did the same inside false activities.
Output when the parameter value is not given(empty).
Output when we gave any value to the parameter
In my Tcl/Tk project, i need to allow my users to mangle a string in a well-defined way.
The idea is, to allow people to declare a "string mangling" proc/expr/function/... in a configuration file, which then gets applied to the strings in question.
I'm a bit worried on how to properly implement that.
Possibilities I have considered so far:
regular expressions
That was my first thought, but there's two caveats:
search/replace with regular expressions in Tcl seems to be awkward. at least with regsub i need to pass the match and replacement parts separately (as opposed to how e.g. sed allows me to pass a single complicated string that does everything for me); there are sed implementations for Tcl, but they look naive and might break rather sooner than later
also regexes can be awkward by themselves; using them to mangle complicated strings is often more complicated than it should be
procs?
Since the target platform is Tcl anyhow, why not use the power of Tcl to do string mangling?
The "function" should have a single input and produce a single output, and ideally it the user should be nudged into doing it right (e.g. not being able to define a proc that requires two arguments) and it be (nigh) impossible to create side-effects (like changing the state of the application).
A simplistic approach would be to use proc mymangler s $body (with $body being the string defined by the user), but there are so many things that can go wrong:
$body assuming a different arg-name (e.g. $x instead of $s)
$body not returning anything
$body changing variables,... in the environment
expressions look more like it (always returning things, not allowing to modify the environment easily), but i cannot make them work on strings, and there's no way to pass a variable without agreeing its name.
So, the best I've come up with so far is:
set userfun {return $s} # user-defined string
proc mymangler s ${userfun}
set output [mymangler $input]
Are there better ways to achieve user-defined string-manglers in Tcl?
You can use apply -- the user provides a 2-element list: the second element is the "proc body", the code that does the mangling; the first element is the variable name to hold the string, this variable is used in the body.
For example:
set userfun {{str} {string reverse $str}}
set input "some string"
set result [apply $userfun $input] ;# => "gnirts emos"
Of course the code you get from the user is any arbitrary Tcl code. You can run it in a safe interpreter:
set userfun {{str} {exec some malicious code; return [string reverse $str]}}
try {
set interp [safe::interpCreate]
set result [$interp eval [list apply $userfun $input]]
puts "mangled string is: $result"
safe::interpDelete $interp
} on error e {
error "Error: $e"
}
results in
Error: invalid command name "exec"
Notes:
a standard Tcl command is used, apply
the user must specify the variable name used in the body.
this scheme does protect the environment:
set userfun {{str} {set ::env(SOME_VAR) "safe slave"; return $str$str}}
set env(SOME_VAR) "main"
puts $env(SOME_VAR)
try {
set interp [safe::interpCreate]
set result [$interp eval [list apply $userfun $input]]
puts "mangled string is: $result"
safe::interpDelete $interp
} on error e {
error "Error: $e"
}
puts $env(SOME_VAR)
outputs
main
mangled string is: some stringsome string
main
if the user does not return a value, then the mangled string is simply the empty string.
The "simplistic" approach is like foreach in that it requires the user to supply a variable name and a script to evaluate that uses that variable, and is a good approach. If you don't want it affecting the rest of the program, run it in a separate interpreter:
set x 0
proc mymangler {name body} {
set i [interp create -safe]
set s "some string to change"
try {
# Build the lambda used by apply here instead of making
# the user do it.
$i eval [list apply [list $name $body] $s]
} on error e {
return $e
} finally {
interp delete $i
}
}
puts [mymangler s { set x 1; string toupper $s }]
puts $x
outputs
SOME STRING TO CHANGE
0
If the person calling this says to use s as a variable and then uses something else in the body, it's on them. Same with providing a script that doesn't return anything.
I'd generally allow the user to specify a command prefix as a Tcl list (most simple command names are trivially suitable for this), which you would then apply to the argument by doing:
set mangled [{*}$commandPrefix $valueToMangle]
This lets people provide pretty much anything they want, especially as they can use apply and a lambda term to mangle things as required. Of course, if you're in a procedure then you're probably actually better off doing:
set mangled [uplevel 1 [list {*}$commandPrefix $valueToMangle]]
so that you're running in the caller's context (change 1 to #0 to use the global context instead) which can help protect your procedure against accidental changes and make using upvar within the mangler easier.
If the source of the mangling prefix is untrusted (what that means depends greatly on your application and deployment) then you can run the mangling code in a separate interpreter:
# Make the safe evaluation context; this is *expensive*
set context [interp create -safe]
# You might want to let them define extra procedures too
# interp invokehidden $context source /the/users/file.tcl
# Use the context
try {
set mangled [interp eval $context [list {*}$commandPrefix $valueToMangle]]
} on error {msg} {
# User supplied something bad; error message in $msg
}
There's various ways to support users specifying the transformation, but if you can expose the fact that you're working with Tcl to them then that's probably easiest and most flexible.
I've got a Jenkinsfile script in groovy which is processing a Java application's application.properties file, which I have just added to with
spring.main.banner-mode: off
In my script I read the application.properties file into a map in memory using a Jenkins add-in library yamlRead and then I output the value again into another file but it comes out as:
spring.main.banner-mode: false
That breaks my Java program on boot with a nasty spring boot error. The spring boot variable expects either OFF, FILE or CONSOLE.
I have no way to change yamlRead but I can change the output script which looks like this:
yaml.each {
key, value -> B: {
// some processing...
sh "echo '$base$key=$value' >> $file"
}
}
}
How can I determine if the map actually has the boolean type (which would be bad since I can't change it) or whether the undesired cast to boolean happens in myy echo >> file?
Or could I somehow force groovy not to infer the booleanness when it reads the input, perhaps with quotes around "off"?
Everything is working as expected. Groovy is not your problem its YAML. The YAML reference says that 'off' is interpreted as 'false' as you can see here
https://yaml.org/refcard.html
The Jenkins yamlRead reads 'off' and transforms it to a boolean with value 'false'.
as Thomas wrote: off is a reserved word in yaml format for boolean false
however you could quote it to force it to be a string:
spring.main.banner-mode: 'off'
in this case spring.main.banner-mode key will have a string value off
to check boolean false value you could use something like:
yaml.each {
key, value -> B: {
// some processing...
sh "echo '$base$key=${ value==false? 'off' : value }' >> $file"
}
}
PS:
instead of calling sh to append to a file one key-value you could use following code:
def values = yaml.collect{k,v-> "$k=$v"}.join("\n")
writeFile( file: file, text: values )
I want to use a date variable in my Given -When- Then, I am doing following but it gives error.
where: "For #sql_date"
variable << condition1
However, In my Spock reports it gives me output like this
Where:
For #Error:sql_date
How do I use sql_date variable in where.
I am generating strings with the names of existing variables. I want to use the strings to create a variable set to the VALUE of the existing variable, but I can't figure out how to achieve this.
Put another way if this helps:
A calling routine sends strings "abc" "cde" etc... Each string is the first several characters of a path variable I've already set. I then append "path" to the passed string to create the full name of the existing variable (e.g., %abcpath%) Now I want to get the value of %abcpath% and put it into a variable I can use it in the current routine.
Thanks for any help.
Here is part of the code I have:
SET abcPath=c:\path_to_abc_dir
SET cdePath=c:\path_to_cde_dir
call :names abc cde ...
:names
For %%G in (%*) do (
set name=%%G
:: Append "path" to name from calling routine
set namepath=!name!path
echo "!namepath!"
:: 1st time through namepath is "abcPath"
:: How to now set a var to the VALUE of %abcPath% set above?
::these don't work:
set dirpath=%%namepath%%
set dirpath=!%%namepath%%!
set dirpath=!%namepath%%%amepath%%!
set dirpath=!!name!path:%dirpath%=%%dirpath%%!
::I want to do things with %dirpath% in this routine:
if not "!dirpath!"=="" (
cd !dirpath!
:: call subroutine to get the number of files in the directory
call :forhere
do other stuff with var dirpath ...
)
)
....
::these don't work:
set dirpath=%%namepath%%
^^........^^ Not a valid variable reference
set dirpath=!%%namepath%%!
^^........^^ Not a valid variable reference
set dirpath=!%namepath%%%amepath%%!
^........^ This has been parsed at start and has no value
set dirpath=!!name!path:%dirpath%=%%dirpath%%!
^^ ^..........................^ two "variables" start and end
Delayed expasion over a value obtained with delayed expansion does not have a obvious syntax, because this does not exist. It can not directly be done and other commands need to be used
....
set "name=%%G"
set "namepath=%%Gpath"
call set "dirpath=%%!namepath!%%"
echo !dirpath!
....
Why or how does it work?
When the line is parsed, the only variable referenced is namepath with delayed expansion. The double percent signs are a escaped percent sign. So the line is translated into
call set "dirpath=%abcpath%"
Now, the call is executed, generating a second parse of the line, obtaining the correct value
This can also be done as
for %%a in ("!namepath!") do set "dirpath=!%%~a!"
In this case, the value inside namepath variable is stored into the for replaceable parameter and used to obtain the value to assign to the dirpath variable
In both cases, two "parse" (in the logic sense) operations are done.
In the first solution the first parse extracts the value of namepath and the second parse (invoked by call command execution) uses this value as a variable name.
In the second solution, we first get the value inside namepath (first "parse") and then this value is used in a new delayed expansion operation to retrieve the value to assign to dirpath