Function return string in a shell script - Programming On Unix

Users browsing this thread: 1 Guest(s)
Tristelune
Members
Hello,

I'm writing a shell script and I have the following problem: I need to return a value from a function in my shell script. I use sh as shell. So until now I have use echo and everything were fine.

I came to the idea to improve my script by displaying what is done in the functions I have written. So I have multiple echo's in my function and the last echo is not the returned value. An Example:

Code:
#! /bin/sh

function coucou() {
    echo "This is a try"
}

result=$(coucou)
echo $result

The script returns

Code:
This is a try

which was expected. Now if I try

Code:
#! /bin/sh

function coucou() {
    echo "This is a try"
    echo "End of function"
}

result=$(coucou)
echo $result

I get

Code:
This is a try End of function

So the echo's are concatenated. I don't know very well what happens, I assume because of the construct $(..) nothing is displayed on the terminal and all echo's are stored in the variable result. Does it work like that ?

In my case it's something like

Code:
function rename(){
      filename=$1
      new_filename=${%.pdf}.txt

      echo "The file $filename will be renamed in $new_filename"
      mv $filename $new_filename

      echo $new_filename
}

file=my_file.pdf
new_filename=$(rename $file)

It's simplified. But the idea is the same: I have some conditions to rename a file and I want to return the new filename if the file has been renamed. But in the same time I want to display some information on the terminal for the user. What are the options ?

Thank you!
movq
Long time nixers
Yes, it works like that, $(...) captures everything that was written to STDOUT.

Now I guess that the "... to STDOUT"-part is news to you. Usually, three channels are associated with each process:
  • STDIN (0): Standard input. Unless told otherwise, most programs read from this channel.
  • STDOUT (1): Standard output. That's where regular output ends up.
  • STDERR (2): Standard error. This channel is meant for error messages or diagnostics.

These channels are not as special as you might think. They're just normal file descriptors. When a process opens another file, it gets file descriptor 3 and so on.

When you use a pipe, you connect STDOUT of the first program with STDIN of the second one: "ls -al | grep foo".

You can choose the desired channel in your script, like this:
Code:
#! /bin/sh

function coucou() {
    echo "This is a try" >&2
    echo "End of function" >&2
    echo "string to return"
}

result=$(coucou)
echo "result: '$result'"

You'll see that the first two strings get written to the terminal directly (because they're written to STDERR), whereas the last string is written to STDOUT and thus ends up as your "return value".

Look up "standard streams" and "shell redirection" to learn more.

(Kind of a philosophical issue: Usually, a tool wouldn't print anything unless there's something important to say. There should be a verbose switch "-v", which the user can use to find out exactly what's going on.)
Tristelune
Members
Thank you very much for this exhaustive answer! So I have two options: the first is to redirect to STDOUT to STDERR. The second is to store the result in a global variable. Perhaps someone has another idea, but for me it's solved.
xero
Long time nixers
i'm personally a fan of backticks (it's POSIX DAMN IT!) e.g.

Code:
#!/bin/sh

dirs=`ls -d */`
for dir in $dirs
do
  echo $dir
done
venam
Administrators
Surprisingly, while quite old, according to "Google Console" this thread is very popular.
It is about returning values from shell functions, or from running a third party program and storing the result. It touches how to not pollute stdout which is going to be the result of the function. The limitation of only manipulating text.
It shows how shell scripting, when staying POSIX compliant, can be quite a hassle.

Do you use a technique that wasn't mentioned in this thread? Or a comment about shell scripting limitation regarding standard inputs and outputs.