Bash: Return a String from Bash Function

How to return a string value from a Bash function

There is no better way I know of. Bash knows only status codes (integers) and strings written to the stdout.

Bash: Return a string from bash function

The return statement used by bash is used to return a numeric value as a status code to be retrieved through $? by the calling function. You can not return a string. See also

  • Returning Values from Bash Functions
  • How to return a string value from a Bash function

You can either use a special global variable as proposed by @konsolebox, or echo the return value inside your function, and use command substitution when calling the function:

makeName()
{
echo "$fileName.$1.log"
}

echo -n "Enter fileName:"
read fileName

name1=$(makeName "type1")
name2=$(makeName "type2")

echo $name1
echo $name2

[UPDATE]

The updated question shows that you intend to read yet another value inside the makeName function, while the function also intends to echo some prompt for the user. So the command substitution approach will not work in that case - you need to use a global variable, like

makeName() {
echo -n "Enter Ext: "
read ext

__="$fileName.$1.$ext.log"
}

echo -n "Enter fileName:"
read fileName

makeName "type1" ; name1=${__}
makeName "type2" ; name2=${__}

echo $name1
echo $name2
$ ./sample.sh 
Enter fileName:filename
Enter Ext: ext1
Enter Ext: ext2
filename.type1.ext1.log
filename.type2.ext2.log

Yet better, for cleaner code and to avoid using global variables inside your function, you could use the approach described at Returning Values from Bash Functions and pass the name of the return variable as parameter, and ideally also pass the fileName as parameter:

makeName() {
local __type=$1
local __fileName=$2
local __resultvar=$3
local ext
local myresult

echo -n "Enter Ext: "
read ext
myresult="$__fileName.$__type.$ext.log"

eval $__resultvar="'$myresult'"
}

echo -n "Enter fileName:"
read fileName

makeName "type1" $fileName theResult ; name1=${theResult}
makeName "type2" $fileName theResult ; name2=${theResult}
echo $myresult

echo $name1
echo $name2

Side Note: See Why should eval be avoided in Bash, and what should I use instead? for a discussion why eval should be avoided. When using bash version 3.1 or higher, you can use printf instead of eval:

...
printf -v "$__resultvar" '%s' "$myresult"
...

And, finally, with bash 4.3 or higher, we can assign the nameref attribute to a variable using declare -n, so that the variable is effectively a reference to another variable:

...
declare -n myresult=$3

myresult="$__fileName.$__type.$ext.log"
...

bash: how to return string with newline from function?

Use printf to print formatted strings.

create_string() {
printf '[%s]\nworld\n' "$1"
}

Can a string be returned from a Bash function without using echo or global variables?

No. Bash doesn't return anything other than a numeric exit status from a function. Your choices are:

  1. Set a non-local variable inside the function.
  2. Use echo, printf, or similar to provide output. That output can then be assigned outside the function using command substitution.

Return value in a Bash function

Although Bash has a return statement, the only thing you can specify with it is the function's own exit status (a value between 0 and 255, 0 meaning "success"). So return is not what you want.

You might want to convert your return statement to an echo statement - that way your function output could be captured using $() braces, which seems to be exactly what you want.

Here is an example:

function fun1(){
echo 34
}

function fun2(){
local res=$(fun1)
echo $res
}

Another way to get the return value (if you just want to return an integer 0-255) is $?.

function fun1(){
return 34
}

function fun2(){
fun1
local res=$?
echo $res
}

Also, note that you can use the return value to use Boolean logic - like fun1 || fun2 will only run fun2 if fun1 returns a non-0 value. The default return value is the exit value of the last statement executed within the function.

how to return a multi-line string from a bash function call ... properly?

Your problem here is that echo always adds a newline to the end of your string - if it already contains one, it will have two. Since you're always "returning" using echo "$result", every time it will add a new one.

You should try using printf "%s" "$result":

ini_buffer="1.2.3.4
"
echo "initial ini_buffer len: ${#ini_buffer}"

IFS= read -rd '' result < <(printf "%s" "$ini_buffer")

echo "result len: ${#result}"

Result:

initial ini_buffer len: 8
result len: 8

shell script function return a string

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

Safest way to return string from bash function (4.3) when function contains other echos

Assuming if you are OK with a minimal disk I/O, you could open a file descriptor to write to a file and then later parse it once the function is complete.

In this example, fd 3 will serve our purpose

doThing() {
echo "stuff"
echo "things"

exec 3<> /tmp/foo
echo "usefulstring" >&3
exec 3>&-
}

and now parse this file using read for a single variable or mapfile if you are passing multiple words to the array. This way, the variable holds the string values even if they contain spaces between.

doThing
read -r str < /tmp/foo

The result would be available in str which you can quote it in conditionals. If your file system keeps /tmp or /var busy, you could use mktemp to create a file on your local directory to use for the fd.

This also satisfies your last requirement - I would like to see the logging echos on stdout, but not the return value.

How to get the content of a function in a string using bash?

Make a dummy function foo(), which just prints "bar":

foo() { echo bar ; }

Now a bash function to print what's in one (or more) functions. Since the contents of a function are indented with 4 spaces, sed removes any lines without 4 leading spaces, then removes the leading spaces as well, and adds a ';' at the end of each function:

# Usage: in_func <function_name1> [ ...<function_name2> ... ]
in_func()
{ while [ "$1" ] ; do \
type $1 | sed -n '/^ /{s/^ //p}' | sed '$s/.*/&;/' ; shift ; \
done ; }

Print what's in foo():

in_func foo

Output:

echo bar;

Assign what's in foo() to the string $baz, then print $baz:

baz="`in_func foo`" ; echo $baz

Output:

echo bar;

Run what's in foo():

eval "$baz"

Output:

bar

Assign what's in foo() to $baz three times, and run it:

baz="`in_func foo foo foo`" ; eval "$baz"

Output:

bar
bar
bar

Returning value from called function in a shell script

A Bash function can't return a string directly like you want it to. You can do three things:

  1. Echo a string
  2. Return an exit status, which is a number, not a string
  3. Share a variable

This is also true for some other shells.

Here's how to do each of those options:

1. Echo strings

lockdir="somedir"
testlock(){
retval=""
if mkdir "$lockdir"
then # Directory did not exist, but it was created successfully
echo >&2 "successfully acquired lock: $lockdir"
retval="true"
else
echo >&2 "cannot acquire lock, giving up on $lockdir"
retval="false"
fi
echo "$retval"
}

retval=$( testlock )
if [ "$retval" == "true" ]
then
echo "directory not created"
else
echo "directory already created"
fi

2. Return exit status

lockdir="somedir"
testlock(){
if mkdir "$lockdir"
then # Directory did not exist, but was created successfully
echo >&2 "successfully acquired lock: $lockdir"
retval=0
else
echo >&2 "cannot acquire lock, giving up on $lockdir"
retval=1
fi
return "$retval"
}

testlock
retval=$?
if [ "$retval" == 0 ]
then
echo "directory not created"
else
echo "directory already created"
fi

3. Share variable

lockdir="somedir"
retval=-1
testlock(){
if mkdir "$lockdir"
then # Directory did not exist, but it was created successfully
echo >&2 "successfully acquired lock: $lockdir"
retval=0
else
echo >&2 "cannot acquire lock, giving up on $lockdir"
retval=1
fi
}

testlock
if [ "$retval" == 0 ]
then
echo "directory not created"
else
echo "directory already created"
fi


Related Topics



Leave a reply



Submit