Pass a function call to child shell - bash

My ksh main_script has a call to another script called_script. The called_script ends up creating a child shell which I want to continue working in. I pass it a function fun that needs to be executed.
called_script <<< '
fun
'
I get an error saying fun: not found [No such file or directory], but when I run the called_script followed by fun manually (i.e. directly without using main_script) it works. It seems to me that the called_script execution defines the function. In that case why does using main_script end up with different result?
Note: I cannot change called_script.

Any function defined within the child process will not be available to the main_script unless you export it :
called_script <<< '
export -f fun
fun
'

Related

Bash - how to process additional parameter in function?

I have the following bash script but im unable to use my defined command "kctl" if i call it with "get pods". Do I maybe have to add a placeholder behind the command at the kctl() funtction or so?
#!/bin/bash
KCTL=$(which kubectl)
KUBECONFIG=$1
kctl() {
$KCTL --kubeconfig=$KUBECONFIG
}
kctl get pods
For some reason I always get back the kubectl help and not a list of pods at the default namespace.
Thanks in advance
Here ktcl is a function on its own, so it has its own parameters. When you use it in the end you pass additional parameters to it but then in the function you do nothing with them.
If your intention is to append the arguments to the command inside the function, you have to write it like this:
kctl() {
$KCTL --kubeconfig=$KUBECONFIG "$#"
}
Notice how the function doesn't see the arguments of the script, as they are shadowed by its own arguments.

Run command substitution inside function when function is called

I have a bash script which have some helper function inside a shared, common file lib.sh. However, some of these functions look like this:
function check_prs {
local labels
labels=$(hub pr show -h "${BRANCH:-}" -F '%L')
if [[ $PRLABELS == *"DOTHING"* ]]
then true
else false
fi
}
The problem is that the command substitution and labels variable assignment is done when the script is loaded (source lib.sh from my main script), regardless of whether the function is called (or when).
Is there a way to only make these command substitutions when the function is actually called? Or some other way to make it behave as everything else in the normal flow of the script?

Using a bash function from a script

What is the right way of assigning the output of lowercase_last2 to another variable? What am I doing wrong below?
I have a shell script test_lowercase_last.sh that defines a couple of functions
#!/bin/bash
function lowercase_last2() (
PART2=/"${1##*/}"
PART1=${1%"$PART2"}
PART2_LOWER=$(echo "$PART2" | tr '[:upper:]' '[:lower:]')
echo ${PART1}${PART2_LOWER}
)
function basic() (
echo "Testing"
)
and another script that means to use them
#!/bin/bash
echo $(basic)
echo $(lowercase_last /home/santiago/Test)
But this is what I get
$ source test_lowercase_last.sh
$ ./test_bash_func.sh
./test_bash_func.sh: line 2: basic: command not found
./test_bash_func.sh: line 3: lowercase_last: command not found
I actually mean to assign the output of lowercase_last2 to another variable, but I guess once I get this right, it should be straightforward.
Then the question.
Source the library in the script you use it from:
#!/bin/bash
source test_lowercase_last.sh
echo "$(basic)"
echo "$(lowercase_last /home/santiago/Test)"
Unless you use export -f lowercase_last basic to export your functions to the environment, they are not automatically inherited by separate shells. (Subshells inherit copies of internal state; but those are fork()ed with no exec() call; when you run a new script, it's across an exec boundary, so it doesn't have access to the original process's non-exported variables).
By the way -- see BashPitfalls #14 re: why echo's arguments should always be quoted when non-constant (and, as an aside, the last table in https://wiki.bash-hackers.org/scripting/obsolete discussing function declaration syntax options).

return a value from shell script, into another shell script

I know how to return an exit code, but I would like to return the result of an operation done in a shell script function, so I can eventually use it in another script or function.
Something like
var1=$(myfunction)
function2 var1
Where myfunction could be something like A+B=C
I looked into "return", but it will return a code, not a value.
I am looking into various sites that show how to write functions, but I don't see how you actually return values.
In C++ you would use return "variable name", but shell script won't allow this. It says that the variable do not exist (which is logical, it is a variable created in a function, so when the function is released, that memory space assigned to it is gone). Can't use global variables since the function may be in one script and the calling function that needs the return value, may be in a different one.
myfunction could be something like A+B=C
Just echo the result:
$ myfunction() { echo $(($1+$2)); }
The above myfunction adds two numbers and echoes the result.
The return value can then be captured just as you had it:
$ var=$(myfunction 12 5)
$ echo $var
17
The construct var=$(myfunction) captures the standard out from myfunction and saves it in var. Thus, when you want to return something from myfunction, just send it to standard, like we did with echo in the example above.
In cases where you want the return value to be carefully formatted, you should consider using printf in place of echo.
More: How to return multiple values
Let's define a function that produces two outputs:
$ f() { echo "output1" ; echo "output2" ; }
$ f
output1
output2
If you want to get those values back separately, the most reliable method is to use bash's arrays:
$ a=($(f))
The above executes f, via $(f) and saves the results in an array called a. We can see what is in a by using declare -p:
$ declare -p a
declare -a a='([0]="output1" [1]="output2")'
I use the same sorta thing for returning values from other scripts to my main script like the title suggests.
At the end of the 2nd script, I echo the variable I want to return to the main script:
#!/bin/bash
# This is the Second Script.
# Store the variables passed from the main script:
VAR1_FROM_MAIN_SCRIPT=$1
VAR2_FROM_MAIN_SCRIPT=$2
# Add the 2 variables and store as another variable to return:
RETURN_THIS=$(($VAR1_FROM_MAIN_SCRIPT + VAR2_FROM_MAIN_SCRIPT))
# This is the variable you are sending back to the main script:
echo "$RETURN_THIS" #<---- This won't print to screen!!!
Then in the main script I pass in a couple variables to, and execute, the 2nd script like this:
#!/bin/bash
# This is the Main Script.
PASS_VAR1_TO_SCRIPT=1
PASS_VAR2_TO_SCRIPT=2
# Call the second script and store it's results in this variable:
RETURN_VARIABLE=$(./secondScriptName "$PASS_VAR1_TO_SCRIPT" "$PASS_VAR2_TO_SCRIPT")
# Display the returned variable from the second script:
echo $RETURN_VARIABLE #<---- Will display 3
The reason the echo in the second script won't print to screen, is because it's running that second script in a subshell from the RETURN_VARIABLE... I know my explanation of the subshell sucks, but that's besides the point...
Also, I know you can source the other script, but this might help others.
In shell scripting you don't return a value but just echo (print) it and caller would capture the output of your script/function to grab the returned value.
Example:
dateval=$(date)
echo $dateval
Wed Apr 23 18:35:45 EDT 2014
Instead of date you can place your function or your shell script.

Shell scripting return values not correct, why?

In a shell script I wrote to test how functions are returning values I came across an odd unexpected behavior. The code below assumes that when entering the function fnttmpfile the first echo statement would print to the console and then the second echo statement would actually return the string to the calling main. Well that's what I assumed, but I was wrong!
#!/bin/sh
fntmpfile() {
TMPFILE=/tmp/$1.$$
echo "This is my temp file dude!"
echo "$TMPFILE"
}
mainname=main
retval=$(fntmpfile "$mainname")
echo "main retval=$retval"
What actually happens is the reverse. The first echo goes to the calling function and the second echo goes to STDOUT. why is this and is there a better way....
main retval=This is my temp file dude!
/tmp/main.19121
The whole reason for this test is because I am writing a shell script to do some database backups and decided to use small functions to do specific things, ya know make it clean instead of spaghetti code. One of the functions I was using was this:
log_to_console() {
# arg1 = calling function name
# arg2 = message to log
printf "$1 - $2\n"
}
The whole problem with this is that the function that was returning a string value is getting the log_to_console output instead depending on the order of things. I guess this is one of those gotcha things about shell scripting that I wasn't aware of.
No, what's happening is that you are running your function, and it outputs two lines to stdout:
This is my temp file dude!
/tmp/main.4059
When you run it $(), bash will intercept the output and store it in the value. The string that is stored in the variable contains the first linebreak (the last one is removed). So what is really in your "retval" variable is the following C-style string:
"This is my temp file dude!\n/tmp/main.4059"
This is not really returning a string (can't do that in a shell script), it's just capturing whatever output your function returns. Which is why it doesn't work. Call your function normally if you want to log to console.

Resources