Bash get output from class - linux

I've got a script, and I want to do something like this :
text1() {
something here
}
show(){
echo test1()
and some text here
}
Basically I want to use output from the first class function in the second class function, how I can do this?

If you want to put to a variable a value that function returns to stdout, use $():
foo() {
printf '%s\n' 'ququ'
}
bar() {
VAR="$(foo)"
echo "$VAR"
}
I. e. functions in GNU Bash (and other shells as well) are like external utilities.

I don't know if this is really what you want, but ...
You must know that bash functions, internal commands and standard tools don't return their output. Instead they write it on stdout. When you don't use any redirection, stdout is the terminal screen where you launched the command.
function text1() {
echo "In text1()"
}
function show(){
test1
echo "In show()"
}
If I call text1 from my terminal:
sh$ text1
In text1()
The function text1 during its execution invokes echo that send output to stdout. I see the result on the console.
sh$ show
In text1()
In show()
Calling show executes text1 (producing the same output as previously) followed by the output of the second echo.
If you want to store in a variable the intermediate result of a function or command, you might use the VAR=$( ...) notation. Think of that like "capturing" the output:
function text1() {
echo "In text1()"
}
function show(){
MYVAR=$(text1)
echo "In show() where MYVAR = ${MYVAR}"
}
Please compare the output now, with the previous case:
sh$ show
In show() where MYVAR = In text1()

Related

Can I only call a function from the terminal rather the whole bash script?

I have a bash script that looks as such:
#!/bin/bash
function one {
echo "I am function one!!"
}
function two {
echo "I am function two!!"
}
one
two
If I simply do bash test.sh both functions are being executed.
What I'd like to do is to call the script from the terminal while also specifying one of the two functions, and executing only it.
Maybe something like: bash test.sh$one() and it should only print out
I am function one!!
Is this possible and if so, how will I go about achieving it?
Thanks!
=========================
EDIT: As per #Waqas suggestion I ended up implementing the below which did the trick for me:
function main {
if [ -z "$1" ]
then
some commands
# else run the given function only
else
$1
fi
}
main "$#"
Thanks!!!
There are many ways to write the code in order to fulfill your requirement. The way I will write the code for this, is the following:
#!/bin/bash
function main {
# If the argument is empty then run both functions else only run provided function as argument $1.
[ -z "$1" ] && { one; two; } || $1
}
function one {
echo "I am function one!!"
}
function two {
echo "I am function two!!"
}
main "$#"
If you only execute the script without passing argument then both functions will run and with passing argument only single function will work.
Example1 (Both functions will run): bash script_name
Example2 (Only function one will run): bash script_name one
Example3 (Only function two will run): bash script_name two
You better separate the files: Move the function definitions in a separate file, say ~/lib/testlib.src. Your test.sh then becomes
#!/bin/bash
. ~/lib/testlib.src
one
two
If you need the definitions in your interactive shell, either do there a . ~/lib/testlib.src manually, or if you want to have them always available, put this statement into your ~/.bashrc.
You could do this by writing a case statement after defining the functions but before any other lines of code.
#!/bin/bash
function one {
echo "I am function one!!"
}
function two {
echo "I am function two!!"
}
case $1 in
one)
one
;;
two)
two
;;
*)
one
two
;;
esac
Which could then be used as:
$ ./test.sh one
# I am function one!!
$ ./test.sh two
# I am function two!!
In the above example I put the body of your script under the *) option, but if it better suits your needs, you could instead have the one) and two) options "exit" after calling their single function:
case $1 in
one)
one
exit 0
;;
two)
two
exit 0
;;
esac
one
two
This is all assuming you are not passing any other arguments to the script and that $1 would be used for the desired function. The case statement would become more complex otherwise.

Redirecting output from a function block to a file in Linux

Just like we redirect output from a for loop block to a file
for ()
do
//do something
//print logs
done >> output file
Similarly in shell script, is there a way to redirect output from a function block to a file, something like this?
function initialize {
//do something
//print something
} >> output file
//call initialize
If not, is there some other way I can achieve that? Please note my function has lot of messages to be printed in a log. Redirecting output to a file at every line would result in a lot of I/O utilization.
Do the redirection when you are calling the function.
#!/bin/bash
initialize() {
echo 'initializing'
...
}
#call the function with the redirection you want
initialize >> your_file.log
Alternatively, open a subshell in the function and redirect the subshell output:
#!/bin/bash
initialize() {
( # opening the subshell
echo 'initializing'
...
# closing and redirecting the subshell
) >> your_file.log
}
# call the function normally
initialize
The way you suggest is actually perfectly valid. The Bash manual gives the function declaration syntax as follows (emphasis mine)1:
Functions are declared using this syntax:
name () compound-command [ redirections ]
or
function name [()] compound-command [ redirections ]
So this would be perfectly valid and replace the contents of outfile with the argument to myfunc:
myfunc() {
printf '%s\n' "$1"
} > outfile
Or, to append to outfile:
myappendfunc() {
printf '%s\n' "$1"
} >> outfile
However, even though you can put the name of your target file into a variable and redirect to that, like this:
fname=outfile
myfunc() { printf '%s\n' "$1"; } > "$fname"
I think think it's much clearer to do the redirection where you call the function – just like recommended in other answers. I just wanted to point out that you can have the redirection as part of the function declaration.
1And this is not a bashism: the POSIX Shell spec also allows redirections in the function definition command.
You can use for exec for shell redirection not sure if it will work for functions
exec > output_file
function initialize {
...
}
initialize
My solution is wrap the function.
init_internal(){
echo "this is init_internal with params: $#"
echo "arg1 $1"
echo "arg2 $2"
}
init() {
local LOG_PATH=$1
echo "LOG at: $LOG_PATH"
init_internal "${#:2}" > ./$LOG_PATH 2>&1
}
init log.log a b c d
cat ./log.log
It outputs:
LOG at: log.log
this is init_internal with params: a b c d
arg1 a
arg2 b

shell script function return a string

I am new to shell scripts, I am trying to create a simple function which will return the concatenated two strings that are passed as parameters. I tried with below code
function getConcatenatedString() {
echo "String1 $1"
echo "String2 $2"
str=$1/$2
echo "Concatenated String ${str}"
echo "${str}"
}
//I am calling the above function
constr=$(getConcatenatedString "hello" "world")
echo "printing result"
echo "${constr}"
echo "exit"
I see the below output when running the script with above code,
printing result
String1 hello
String2 world
Concatenated String hello/world
hello/world
exit
If you look at the code I am first calling the function and then I am echoing "printing result" statement, but the result is first comes the "printing result" and echos the statement inside the function. Is the below statement calling the function
constr=$(getConcatenatedString "hello" "world")
or
echo ${constr}
is calling the function ?
Because if I comment out #echo ${constr} then nothing is getting echoed !!! Please clarify me.
The first is calling the function and storing all of the output (four echo statements) into $constr.
Then, after return, you echo the preamble printing result, $constr (consisting of four lines) and the exit message.
That's how $() works, it captures the entire standard output from the enclosed command.
It sounds like you want to see some of the echo statements on the console rather than capturing them with the $(). I think you should just be able to send them to standard error for that:
echo "String1 $1" >&2
paxdiablo's solution is correct. You cannot return a string from a function, but you can capture the output of the function or return an integer value that can be retrieved by the caller from $?. However, since all shell variables are global, you can simply do:
getConcatenatedString() { str="$1/$2"; }
getConcatenatedString hello world
echo "Concatenated String ${str}"
Note that the function keyword is redundant with (), but function is less portable.
A more flexible, but slightly harder to understand approach is to pass a variable name, and use eval so that the variable becomes set in the caller's context (either a global or a function local). In bash:
function mylist()
{
local _varname=$1 _p _t
shift
for _p in "$#"; do
_t=$_t[$_p]
done
eval "$_varname=\$_t"
}
mylist tmpvar a b c
echo "result: $tmpvar"
On my Linux desktop (bash-3.2) it's approx 3-5x faster (10,000 iterations) than using ``, since the latter has process creation overheads.
If you have bash-4.2, its declare -g allows a function to set a global variable, so you can replace the unpretty eval with:
declare -g $_varname="$_t"
The eval method is similar to TCL's upvar 1, and declare -g is similar to upvar #0.
Some shell builtins support something similar, like bash's printf with "-v", again saving process creation by assigning directly to a variable instead of capturing output (~20-25x faster for me).

How to return data from a bash shell script subroutine?

Given the following two executable scripts:
----- file1.sh
#!/bin/sh
. file2.sh
some_routine data
----- file2.sh
#!/bin/sh
some_routine()
{
#get the data passed in
localVar=$1
}
I can pass 'data' to a subroutine in another script, but I would also like to return data.
Is it possible to return information from some_routine?
e.g: var = some_routine data
Have the subroutine output something, and then use $() to capture the output:
some_routine() {
echo "foo $1"
}
some_var=$(some_routine bar)
It's not allowed, just set the value of a global variable (..all variables are global in bash)
if
some_routine() {
echo "first"
echo "foo $1"
}
some_var=$(some_routine "second")
echo "result: $some_var"
they are ok.But the result seems to be decided by the first "echo".Another way is use "eval".
some_var return "first"
some_routine()
{
echo "cmj"
eval $2=$1
}
some_routine "second" some_var
echo "result: $some_var"
in this way, some_var return "second".The bash don't return a string directly.So we need some tricks.

Get a list of function names in a shell script [duplicate]

This question already has answers here:
How do I list the functions defined in my shell? [duplicate]
(8 answers)
Closed 4 years ago.
I have a Bourne Shell script that has several functions in it, and allows to be called in the following way:
my.sh <func_name> <param1> <param2>
Inside, func_name() will be called with param1 and param2.
I want to create a help function that would just list all available functions, even without parameters.
The question: how do I get a list of all function names in a script from inside the script?
I'd like to avoid having to parse it and look for function patterns. Too easy to get wrong.
Update: the code. Wanted my help() function be like main() - a function added to the code is added to the help automatically.
#!/bin/sh
# must work with "set -e"
foo ()
{
echo foo: -$1-$2-$3-
return 0
}
# only runs if there are parameters
# exits
main ()
{
local cmd="$1"
shift
local rc=0
$cmd "$#" || rc=$?
exit $rc
}
if [[ "$*" ]]
then
main "$#"
die "how did we get here?"
fi
You can get a list of functions in your script by using the grep command on your own script. In order for this approach to work, you will need to structure your functions a certain way so grep can find them. Here is a sample:
$ cat my.sh
#!/bin/sh
function func1() # Short description
{
echo func1 parameters: $1 $2
}
function func2() # Short description
{
echo func2 parameters: $1 $2
}
function help() # Show a list of functions
{
grep "^function" $0
}
if [ "_$1" = "_" ]; then
help
else
"$#"
fi
Here is an interactive demo:
$ my.sh
function func1() # Short description
function func2() # Short description
function help() # Show a list of functions
$ my.sh help
function func1() # Short description
function func2() # Short description
function help() # Show a list of functions
$ my.sh func1 a b
func1 parameters: a b
$ my.sh func2 x y
func2 parameters: x y
If you have "private" function that you don't want to show up in the help, then omit the "function" part:
my_private_function()
{
# Do something
}
typeset -f returns the functions with their bodies, so a simple awk script is used to pluck out the function names
f1 () { :; }
f2 () { :; }
f3 () { :; }
f4 () { :; }
help () {
echo "functions available:"
typeset -f | awk '/ \(\) $/ && !/^main / {print $1}'
}
main () { help; }
main
This script outputs:
functions available:
f1
f2
f3
f4
help
You call this function with no
arguments and it spits out a
"whitespace" separated list of
function names only.
function script.functions () {
local fncs=`declare -F -p | cut -d " " -f 3`; # Get function list
echo $fncs; # not quoted here to create shell "argument list" of funcs.
}
To load the functions into an array:
declare MyVar=($(script.functions));
Of course, common sense dictates that
any functions that haven't been
sourced into the current file before
this is called will not show up in the
list.
To Make the list read-only and
available for export to other scripts
called by this script:
declare -rx MyVar=($(script.functions));
To print the entire list as newline
separated:
printf "%s\n" "${MyVar[#]}";
The best thing to do is make an array (you are using bash) that contains functions that you want to advertise and have your help function iterate over and print them.
Calling set alone will produce the functions, but in their entirety. You'd still have to parse that looking for things ending in () to get the proverbial symbols.
Its also probably saner to use something like getopt to turn --function-name into function_name with arguments. But, well, sane is relative and you have not posted code :)
Your other option is to create a loadable for bash (a fork of set) that accomplishes this. Honestly, I'd prefer going with parsing before writing a loadable for this task.

Resources