Exceuting function in Shell file from command - bash

In my shellFile.sh I wrote this function:
#!/bin/bash
myFunction(){
echo 1
}
I tried to call the function from the command line this way:
shellFile.sh
shellFile.sh myFunction
After this two lines there is no output and no errors. I apologize if this question is asked before but I couldn't find it.

you can call your function inside your script like this
#!/bin/bash
myFunction(){
echo 1
}
myFunction
If you want to use the function interactively you can source the script, then call the function from the command line.
$ source shellFile.sh
$ myFunction
1

If you want the function to be available from the command line, you need to create the function in the current shell, using the dot . command, or in Bash its workalike source:
$ . shellFile.sh
$ myFunction
1
$

I suggest:
#!/bin/bash
myFunction(){
echo 1
}
$1
Usage: ./shellFile.sh myFunction
Output:
1

You need to call the function in the script:
#!/bin/bash
myFunction() {
echo 1
}
myFunction

Related

Pass function name as argument when running bash script

Assuming I have the following script:
#!/bin/bash
function hello (){
echo hello,
}
function world (){
echo world!
}
Is it possible to select the functions to run while I start the script?
For exmaple:
./test.sh hello world
output:
hello,world!
Just iterate over the arguments and run them.
for i in "$#"; do
"$i"
done
Do not use function name(), just name(). See https://wiki.bash-hackers.org/scripting/obsolete . Check your scripts with shellcheck .
You can use eval command to execute first argument.
#!/bin/bash
function hello (){
echo hello,
}
function world (){
echo world!
}
eval $1

How could I import a certain function in another shell script while don't execute the entire code in it?

I have two shell script, with one script need to import a function in another one, but when I use . to source that script, not only the function was executed, but also the other codes inside that script.
Like I have a script.sh
#!/bin/bash
func()
{
echo "func was called"
}
echo "This is script.sh"
And a test script test.sh
#!/bin/bash
. ./script.sh
echo $(func)
When I run func.sh, the result is like this
This is script.sh
func was called
So, my question is how could I just run the func without the echo in the last line of script.sh
When you are not sure which lines you need to delete, you can try to extracht all set of lines starting with something() until a } at the first position of the line. This might fail (now or in the future), you can consider extracting the functions.
util.sh (first line is a trick avoiding calling it without sourcing)
#!/bin/echo "This file should be sourced."
func()
{
echo "func was called"
}
Modified script.sh
#!/bin/bash
. ./util.sh
echo "This is script.sh"
And test.sh
#!/bin/bash
. ./util.sh
# echo not needed in "echo $(func)"
func

Call from script A a function defined in script B - without executing the body of script B [duplicate]

I have a shell script that I would like to test with shUnit. The script (and all the functions) are in a single file since it makes installation much easier.
Example for script.sh
#!/bin/sh
foo () { ... }
bar () { ... }
code
I wanted to write a second file (that does not need to be distributed and installed) to test the functions defined in script.sh
Something like run_tests.sh
#!/bin/sh
. script.sh
# Unit tests
Now the problem lies in the . (or source in Bash). It does not only parse function definitions but also executes the code in the script.
Since the script with no arguments does nothing bad I could
. script.sh > /dev/null 2>&1
but I was wandering if there is a better way to achieve my goal.
Edit
My proposed workaround does not work in the case the sourced script calls exit so I have to trap the exit
#!/bin/sh
trap run_tests ERR EXIT
run_tests() {
...
}
. script.sh
The run_tests function is called but as soon as I redirect the output of the source command the functions in the script are not parsed and are not available in the trap handler
This works but I get the output of script.sh:
#!/bin/sh
trap run_tests ERR EXIT
run_tests() {
function_defined_in_script_sh
}
. script.sh
This does not print the output but I get an error that the function is not defined:
#!/bin/sh
trap run_tests ERR EXIT
run_tests() {
function_defined_in_script_sh
}
. script.sh | grep OUTPUT_THAT_DOES_NOT_EXISTS
This does not print the output and the run_tests trap handler is not called at all:
#!/bin/sh
trap run_tests ERR EXIT
run_tests() {
function_defined_in_script_sh
}
. script.sh > /dev/null
According to the “Shell Builtin Commands” section of the bash manpage, . aka source takes an optional list of arguments which are passed to the script being sourced. You could use that to introduce a do-nothing option. For example, script.sh could be:
#!/bin/sh
foo() {
echo foo $1
}
main() {
foo 1
foo 2
}
if [ "${1}" != "--source-only" ]; then
main "${#}"
fi
and unit.sh could be:
#!/bin/bash
. ./script.sh --source-only
foo 3
Then script.sh will behave normally, and unit.sh will have access to all the functions from script.sh but will not invoke the main() code.
Note that the extra arguments to source are not in POSIX, so /bin/sh might not handle it—hence the #!/bin/bash at the start of unit.sh.
Picked up this technique from Python, but the concept works just fine in bash or any other shell...
The idea is that we turn the main code section of our script into a function. Then at the very end of the script, we put an 'if' statement that will only call that function if we executed the script but not if we sourced it. Then we explicitly call the script() function from our 'runtests' script which has sourced the 'script' script and thus contains all its functions.
This relies on the fact that if we source the script, the bash-maintained environment variable $0, which is the name of the script being executed, will be the name of the calling (parent) script (runtests in this case), not the sourced script.
(I've renamed script.sh to just script cause the .sh is redundant and confuses me. :-)
Below are the two scripts. Some notes...
$# evaluates to all of the arguments passed to the function or
script as individual strings. If instead, we used $*, all the
arguments would be concatenated together into one string.
The RUNNING="$(basename $0)" is required since $0 always includes at
least the current directory prefix as in ./script.
The test if [[ "$RUNNING" == "script" ]].... is the magic that causes
script to call the script() function only if script was run directly
from the commandline.
script
#!/bin/bash
foo () { echo "foo()"; }
bar () { echo "bar()"; }
script () {
ARG1=$1
ARG2=$2
#
echo "Running '$RUNNING'..."
echo "script() - all args: $#"
echo "script() - ARG1: $ARG1"
echo "script() - ARG2: $ARG2"
#
foo
bar
}
RUNNING="$(basename $0)"
if [[ "$RUNNING" == "script" ]]
then
script "$#"
fi
runtests
#!/bin/bash
source script
# execute 'script' function in sourced file 'script'
script arg1 arg2 arg3
If you are using Bash, a similar solution to #andrewdotn's approach (but without needing an extra flag or depending on the script name) can be accomplished by using BASH_SOURCE array.
script.sh:
#!/bin/bash
foo () { ... }
bar () { ... }
main() {
code
}
if [[ "${#BASH_SOURCE[#]}" -eq 1 ]]; then
main "$#"
fi
run_tests.sh:
#!/bin/bash
. script.sh
# Unit tests
If you are using Bash, another solution may be:
#!/bin/bash
foo () { ... }
bar () { ... }
[[ "${FUNCNAME[0]}" == "source" ]] && return
code
I devised this. Let's say our shell library file is the following file, named aLib.sh:
funcs=("a" "b" "c") # File's functions' names
for((i=0;i<${#funcs[#]};i++)); # Avoid function collision with existing
do
declare -f "${funcs[$i]}" >/dev/null
[ $? -eq 0 ] && echo "!!ATTENTION!! ${funcs[$i]} is already sourced"
done
function a(){
echo function a
}
function b(){
echo function b
}
function c(){
echo function c
}
if [ "$1" == "--source-specific" ]; # Source only specific given as arg
then
for((i=0;i<${#funcs[#]};i++));
do
for((j=2;j<=$#;j++));
do
anArg=$(eval 'echo ${'$j'}')
test "${funcs[$i]}" == "$anArg" && continue 2
done
unset ${funcs[$i]}
done
fi
unset i j funcs
At the beginning it checks and warns for any function name collision detected.
At the end, bash has already sourced all functions, so it frees memory from them and keeps only the ones selected.
Can be used like this:
user#pc:~$ source aLib.sh --source-specific a c
user#pc:~$ a; b; c
function a
bash: b: command not found
function c
~

bash FUNCNAME value expanding

I have one lib-file. It has one wrapper-like substitution of ponOS function. I want to display in function ponOS name of function where it is called from.
$> cat ./parasha_lib.sh
#!/bin/bash
function ponOS {
echo "$1: hello from ponOS"
}
ponOS='ponOS ${FUNCNAME}'
But, what I see is that this solution did not work as well as I want.
$> cat ./test.sh
#!/bin/bash
source ./parasha_lib.sh
function main {
echo "message from ${FUNCNAME}"
ponOS
}
main
So, I've got
$> ./test.sh
message from main
: hello from ponOS
But I wanna get this:
$> ./test.sh
message from main
main: hello from ponOS
What should I do?
One of the important things here is that ./test.sh shouldn't be modified (ponOS ${FUNCNAME} it's not the solution).
To do that, you need to set ponOS as an alias so that ${FUNCNAME} is expanded when called within the main function and not when the script is sourced.
Modify ./parasha_lib.sh to:
#!/bin/bash
function ponOS {
echo "$1: hello from ponOS"
}
shopt -s expand_aliases # enable alias expansion
alias ponOS='ponOS ${FUNCNAME}' # create an alias to call ponOS
Note that shopt -s expand_aliases is required to enable alias expansion. From the bash manpage:
Aliases are not expanded when the shell is not interactive, unless the expand_aliases shell option is set using shopt
Now, without changing test.sh we get the desired output:
[me#home]$ ./test.sh
message from main
main: hello from ponOS
See FUNCNAME at http://www.gnu.org/software/bash/manual/bash.html#Bash-Variables
parasha_lib.sh
#!/bin/bash
function ponOS {
echo "${FUNCNAME[1]}: hello from ponOS"
}
test.sh
#!/bin/bash
source ./parasha_lib.sh
function main {
echo "message from ${FUNCNAME}"
ponOS
}
main
Result ./test.sh
message from main
main: hello from ponOS

Bash - How to call a function declared in a parent shell?

I am writing a bash script that calls functions declared in the parent shell, but it doesn't work.
For example:
$ function myfunc() { echo "Here in myfunc" ; }
$ myfunc
Here in myfunc
$ cat test.sh
#! /bin/bash
echo "Here in the script"
myfunc
$ ./test.sh
Here in the script
./test.sh: line 4: myfunc: command not found
$ myfunc
Here in myfunc
As you can see the script ./test.sh is unable to call the function myfunc, is there some way to make that function visible to the script?
Try
$ export -f myfunc
in the parent shell, to export the function.
#OP, normally you would put your function that every script uses in a file, then you source it in your script. example, save
function myfunc() { echo "Here in myfunc" ; }
in a file called /path/library. Then in your script, source it like this:
#!/bin/bash
. /path/library
myfunc
This also works but I noticed ${0} takes parent's value:
Maybe more useful if you don't want to have a bunch of export calls in your scripts.
script1:
#!/bin/bash
func()
{
echo func "${1}"
}
func "1"
$(. ./script2)
script2:
#!/bin/bash
func "2"
Output:
[mymachine]# ./script1
func 1
func 2

Resources