1

I am trying to learn linux bash scripting. I have a script and I want to get the return value of this script and store it in a variable.

Any help is welcome.

Thank you in advance.

#!/bin/bash
HOST_NAME=$1

{ echo "105" ; sleep 5; } | telnet $HOST_NAME 9761;
Cyrus
  • 84,225
  • 14
  • 89
  • 153
Jason A
  • 89
  • 1
  • 8
  • Possible duplicate of [Capturing exit status of a failed command in a shell script](https://stackoverflow.com/questions/40259747/capturing-exit-status-of-a-failed-command-in-a-shell-script) – oguz ismail Apr 27 '19 at 14:15
  • Think about using ssh (best with public-key-auth) to execute remote commands. First and mot important: no clear text passwords are used. Second easier managing because of any interactive welcome or message-of-day notices that telnet regularly do. Third, easy(er) executing of complete scripts. – Wiimm Apr 27 '19 at 19:15

4 Answers4

3

To avoid confusion don't think/talk of it as a return value, think of it as what it is - an exit status.

In most programming languages you can capture the return value of a function by capturing whatever that function returns in a variable, e.g. with a C-like language :

int foo() {
    printf("35\n");
    return 7;
}

void main() {
    int var;
    var=foo();
}

the variable var in main() after calling foo() will hold the value 7 and 35 will have been printed to stdout. In shell however with similar-looking code:

foo() {
    printf "35\n"
    return 7
}

main() {
    local var
    var=$(foo)
}

var will have the value 35 and the unmentioned builtin variable $? which always holds the exit status of the last command run will have the value 7. If you wanted to duplicate the C behavior where 35 goes to stdout and var contains 7 then that'd be:

foo() {
    printf "35\n"
    return 7
}

main() {
    local var
    foo
    var=$?
}

The fact that shell functions use the keyword return to report their exit status is confusing at first if you're used to other Algol-based languages like C but if they used exit then it'd terminate the whole process so they had to use something and it quickly becomes obvious what it really means.

So when taking about shell scripts and functions use the words "output" and "exit status", not "return" which some people in some contexts will assume means either of those 2 things, and that'll avoid all confusion.

Btw to avoid making things even more complicated I said above that $? is a variable but it's really the value of the "special parameter" ?. If you really want to understand the difference right now then see https://www.gnu.org/software/bash/manual/bash.html#Shell-Parameters for a discussion of shell parameters which includes "special parameters" like ? and #, "positional parameters" like 1 and 2, and "variables" like HOME and var as used in my script above.

Ed Morton
  • 188,023
  • 17
  • 78
  • 185
  • 1
    Good answer. Probably it's additionally worth to mention that the data type of the exit status is limited to an unsigned char, in contrast to other programming languages where a function can return any datatype – hek2mgl Apr 27 '19 at 21:18
  • 1
    @hek2mgl: that's not the full story. Where it is true that the status is the low-order 8-bits in C, the return value from `wait(3)` and `waitpid(3)` is a `pid_t` type (often an `unsigned int` but implementation dependant). – cdarke Apr 28 '19 at 09:16
  • 1
    Hi Ed, Thanks a lot – Jason A May 01 '19 at 20:17
1

The $? shell variable stores the return value, however with the Linux telnet client this may not be as useful as you think. The client will return 1 if the remote host closes the connection (or any remote or network error occurs) and 0 if the local client side closes the connection successfully. The problem being that many services are written so that they send data and then close the TCP connection themselves without waiting for the client:

$ telnet time-b.timefreq.bldrdoc.gov 13
Trying 132.163.96.2...
Connected to time-b-b.nist.gov.
Escape character is '^]'.

58600 19-04-27 13:56:16 50 0 0 736.0 UTC(NIST) *
Connection closed by foreign host.
$ echo $?
1

Even if the client sends a command to the server to quit over the TCP stream, this still results in the remote side closing the connection, with the same result:

$ telnet mail.tardis.ed.ac.uk 25
Trying 193.62.81.50...
Connected to isolus.tardis.ed.ac.uk.
Escape character is '^]'.
220 isolus.tardis.ed.ac.uk ESMTP Postfix (Debian/GNU)
QUIT
221 2.0.0 Bye
Connection closed by foreign host.
$ echo $?
1

So, you're going to get a 1 no matter what really. If you want the return value of a remote script, this is easier with ssh like this:

$ ssh ssh.tardis.ed.ac.uk "exit 5"
THE TARDIS PROJECT  |  pubpubpubpubpubpubpubpubpub  |  Authorised access only
$ echo $?
5

As far as I know the only time telnet would return zero (i.e. success) is if you escape and quite the client, like this:

$ telnet www.google.com 80
Trying 216.58.210.36...
Connected to www.google.com.
Escape character is '^]'.
^]

telnet> quit
Connection closed.
$ echo $?
0

Hope this helps.

grkvlt
  • 2,577
  • 1
  • 21
  • 38
  • "*The $? shell variable*" I know this is being picky, but `$?` is not the name of a variable, it is the *value* of the variable `?`. The `$` prefix is a unary operator which gives the value, as I'm sure you know. Sorry. – cdarke Apr 27 '19 at 15:26
  • 1
    I've seen both `$VAR` and `VAR` used in different documentation, I think it depends on what level of expertise with shell programming the reader is expected to have... – grkvlt Apr 27 '19 at 15:40
  • I have seen it incorrectly named elsewhere as well. It leads to confusion when using commands like `export` (which is a very basic command) and `declare` where the variable name is used, not prefixed with `$`. I find with beginners it is better to be correct about which is the name and exactly what the `$` is, otherwise you get problems later on. – cdarke Apr 27 '19 at 15:48
1

It depends on what you mean by return value.

Processes (on UNIX-like systems) can return to a shell a single unsigned byte as an exit status, so that gives a value in the range 0-255. By convention zero means success and any other value indicates a failure.

(In lower-level languages, like C, you can get more than just this exit status, but that's not visible in bash).

The exit status of the last command run is stored in variable ?, so you can get its value from $?, however since many programs only return either 0 (it worked) or 1 (it didn't work), that's not much use.

Bash conditionals, like if and while test for success (exit code of 0) or failure (exit code of non-zero):

if some-command
then
    echo "It worked"
else
    echo "It didn't work"
fi

However ....

If you mean you want to get the output from the script, that's a different matter. You can capture it using:

var=$(some-command)

But wait, that only captures normal output, routed to a stream called stdout (file descriptor 1), it does not capture error messages which most programs write to a stream called stderr (file descriptor 2). To capture errors as well you need to redirect file descriptor 2 to file descriptor 1:

var=$(some-command 2>&1)

The output text is now in variable var.

cdarke
  • 42,728
  • 8
  • 80
  • 84
0

The ? variable always stores the exit code of the previous command.

You can retrieve the value with $?.

Some context: http://tldp.org/LDP/abs/html/exit-status.html

Adam
  • 709
  • 4
  • 16