How can I run a sub function in Bash - bash

How can I run a 'sub function' from a script in command line? Example:
#script_1.sh
main_function() {
sub_function() {
echo "hello world"
}
}
I tried to source this file and call the function from another script:
#script_2.sh
source script_1.sh
sub_function
But I get
script_2.sh: line 3: sub_function: command not found
while I expected to just get hello world.

Thus defined the sub_function will be defined after function is called.
So:
#script_1.sh
function() {
sub_function() {
#cmd
}
}
#script_2.sh
source script_1.sh
function
sub_function
... should work ... except you should rename function, as it's a reserved word

The step missing in your question is to invoke function first - its action is to define sub_function.
Note that sub_function doesn't 'belong' to function in any way - its definition is just a side-effect of running function.
P.S. I assume you aren't really trying to call it function - that's a reserved word in bash.

Related

Groovy parameter to shell script

I've been trying to separate my code into two different files: callTheFunction.groovy and theFunction.groovy.
As you can see from the name of the file:
callTheFunction.groovy calls the function defined in theFunction.groovy, passing random values in as parameters.
theFunction is a shell script - inside groovy function - which is supposed to use the parameters passed from callTheFunction.
PROBLEM:
The shell script does not recognize/understand the arguments, the variables are empty, no value.
theFunction.groovy
def call(var1, var2) {
sh '''
echo "MY values $var1 and $var2"
'''
}
callTheFunction.groovy
def call {
pipeline {
stages {
stage ('myscript') {
steps {
theFunction("Value1", "Value2")
}
}
}
}
}
OUTPUT FROM PIPELINE:
MY values and
I am aware that there are similar issues out there:
Pass groovy variable to shell script
How to assign groovy variable to shell variable
UPDATES
You can use environment variable without having environment {}
Use environment variables like the ones i have used here (i refactored your code a little bit). Using triple single quotes for shell script for loop and adding grrovy variable to it:
def callfunc() {
sh '''
export s="key"
echo $s
for i in $VARENV1
do
echo "Looping ... i is set to $i"
done
'''
}
pipeline {
agent { label 'agent_1' }
stages {
stage ('Run script') {
steps {
script {
env.VARENV1 = "Peace"
}
callfunc()
}
}
}
}
OUTPUT:
Reference:
Jenkins - Passing parameter to groovy function

how to use choice parameter in Jenkins pipeline in batch command

how to use choice parameter in Jenkins declarative pipeline in batch command.
I'm using following stage:
choice(
choices: 'apply\ndestroy\n',
description: '',
name: 'DESTROY_OR_APPLY')
stage ('temp') {
steps {
echo "type ${params.DESTROY_OR_APPLY}"
bat'echo "type01 ${params.DESTROY_OR_APPLY}"'
bat'echo "type01 %{params.DESTROY_OR_APPLY}%"'
bat'echo type01 [${params.DESTROY_OR_APPLY}]'
}
echo does resolve to correct parameter value but under bat none of the above code works.
You almost got the syntax right.
If you change it to one of the below options, the bat command receives the value of your choice.
steps {
bat "echo type01 ${DESTROY_OR_APPLY}"
}
or
steps {
bat 'echo type01 ' + DESTROY_OR_APPLY
}
You can also use ${params.DESTROY_OR_APPLY} in the first or params.DESTROY_OR_APPLY in the second example if you want to use the params definition consequently in your code.

yargs .command error: second argument to option must be an object

Suppose I have a file "test.js":
var args = require('yargs')
.command('command', 'command usage here', {alias: "c"} )
.argv;
Then I run:
>node test command
I got this error:
second argument to option must be an object
If I remove the 3rd parameter of .command:
var args = require('yargs')
.command('command', 'command usage here')
.argv;
Everything is fine.
I must make a dumb mistake. But I just cannot figure it out.
Thanks
Your 3rd argument is not required, that's why it works when you remove it. I'm pretty sure the 3rd argument has to be a function call.
var args = require('yargs')
.command('command',
'command explanation',
function(yargs){
//insert yargs.options here
yargs.options({
c:{
demand: true,//if you require the command
alias: 'c',// you will enter -c to use it
description: 'explain what it does'
}
});
})
.argv;
an example of usage might be:
C:\WorkingDirectory>node app.js command -c run
your code could include console.log(args.c);//prints out run

How can I run all functions in a bash script, in the order in which they are declared without explicitly calling the function? [duplicate]

This question already has answers here:
Get a list of function names in a shell script [duplicate]
(4 answers)
Closed 6 years ago.
Lets say I have a script that has a bunch of functions that act like test cases. So for example:
#!/bin/bash
...
function testAssertEqualsWithStrings () {
assertEquals "something" "something"
}
testAssertEqualsWithStrings <--- I dont want to do this
function testAssertEqualsWithIntegers () {
assertEquals 10 10
}
testAssertEqualsWithIntegers <--- I dont want to do this
function testAssertEqualsWithIntegers2 () {
assertEquals 5 $((10 - 5))
}
testAssertEqualsWithIntegers2 <--- I dont want to do this
function testAssertEqualsWithDoubles () {
assertEquals 5.5 5.5
}
testAssertEqualsWithDoubles <--- I dont want to do this
...
Is there a way I can call of these functions in order without having to actually use that explicit function call underneath each test case? The idea is that the user shouldnt have to manage calling the functions. Ideally, the test suite library would do it for them. I just need to know if this is even possible.
Edit: The reason why I dont use just the assert methods is so I can have meaningful output. My current setup allows me to have output such as this:
...
LineNo 14: Passed - testAssertEqualsWithStrings
LineNo 19: Passed - testAssertEqualsWithIntegers
LineNo 24: Passed - testAssertEqualsWithIntegers2
LineNo 29: Passed - testAssertEqualsWithDoubles
LineNo 34: Passed - testAssertEqualsWithDoubles2
...
LineNo 103: testAssertEqualsWithStringsFailure: assertEquals() failed. Expected "something", but got "something else".
LineNo 108: testAssertEqualsWithIntegersFailure: assertEquals() failed. Expected "5", but got "10".
LineNo 115: testAssertEqualsWithArraysFailure: assertEquals() failed. Expected "1,2,3", but got "4,5,6".
LineNo 120: testAssertNotSameWithIntegersFailure: assertNotSame() failed. Expected not "5", but got "5".
LineNo 125: testAssertNotSameWithStringsFailure: assertNotSame() failed. Expected not "same", but got "same".
...
EDIT: Solution that worked for me
function runUnitTests () {
testNames=$(grep "^function" $0 | awk '{print $2}')
testNamesArray=($testNames)
beginUnitTests #prints some pretty output
for testCase in "${testNamesArray[#]}"
do
:
eval $testCase
done
endUnitTests #prints some more pretty output
}
Then I call runUnitTests at the bottom of my test suite.
If you just want to run these functions without calling them, why declare them as functions in the first place?
You either need them to be functions because you are using them multiple times and need the calls to be different each time, in which case I don't see an issue.
Otherwise you just want to run each function once without calling them, which is just running the command. Remove all the function declarations and just call each line.
For this example
#!/bin/bash
...
assertEquals "something" "something" #testAssertEqualsWithStrings
assertEquals 10 10 #testAssertEqualsWithIntegers
assertEquals 5 $((10 - 5)) #testAssertEqualsWithIntegers2
assertEquals 5.5 5.5 #testAssertEqualsWithDoubles
...

dynamic usage of attribute in recipe

I am trying to increment the value and use in another resource dynamically in recipe but still failing to do that.
Chef::Log.info("I am in #{cookbook_name}::#{recipe_name} and current disk count #{node[:oracle][:asm][:test]}")
bash "beforeTest" do
code lazy{ echo #{node[:oracle][:asm][:test]} }
end
ruby_block "test current disk count" do
block do
node.set[:oracle][:asm][:test] = "#{node[:oracle][:asm][:test]}".to_i+1
end
end
bash "test" do
code lazy{ echo #{node[:oracle][:asm][:test]} }
end
However I'm still getting the error bellow:
NoMethodError ------------- undefined method echo' for Chef::Resource::Bash
Cookbook Trace: ---------------
/var/chef/cache/cookbooks/Oracle11G/recipes/testSplit.rb:3:in block (2 levels) in from_file'
Resource Declaration: ---------------------
# In /var/chef/cache/cookbooks/Oracle11G/recipes/testSplit.rb
1: bash "beforeTest" do
2: code lazy{
3: echo "#{node[:oracle][:asm][:test]}"
4: }
5: end
Please can you help how lazy should be used in bash? If not lazy is there any other option?
bash "beforeTest" do
code lazy { "echo #{node[:oracle][:asm][:test]}" }
end
You should quote the command for the interpolation to work; if not, ruby would search for an echo command, which is unknown in ruby context (thus the error you get in log).
Warning: lazy has to be for the whole resource attribute; something like this WON'T work:
bash "beforeTest" do
code "echo node asm test is: #{lazy { node[:oracle][:asm][:test]} }"
end
The lazy evaluation takes a block of ruby code, as decribed here
You may have a better result with the log resource like this:
log "print before" do
message lazy { "node asm test is #{node[:oracle][:asm][:test]}" }
end
I've been drilling my head solving this problem until I came up with lambda expressions. But yet just using lambda didn't help me at all. So I thought of using both lambda and lazy evaluation. Though lambda is already lazy loading, when compiling chef recipe's, the resource where you call the lambda expression is still being evaluated. So to prevent it to being evaluated (somehow), I've put it inside a lazy evaluation string.
The lambda expression
app_version = lambda{`cat version`}
then the resource block
file 'tmp/validate.version' do
user 'user'
group 'user_group'
content lazy { app_version.call }
mode '0755'
end
Hope this can help others too :) or if you have some better solution please do let me know :)

Resources