3

I'm currently trying to write a simple bash script that connects to my webapi downloads 1 line and uses this line on as a variable. The retrieving itself works just fine:

#!/bin/bash
exec 5<>/dev/tcp/me2stats.eu/5005 # No worries this is a public API ;)
printf "GET /gethighscore?level=1 HTTP/1.1\r\n\r\n" >&5
cat <&5

But I'm having trouble storing the output into a variable, this just outputs a blank line:

output=$(cat <&5)
echo $output

while read line skips the last line (the one I want!):

while read line; do
  echo $line
done <&5

I'm not willing to use wget or curl because I don't want to bloat my docker images even further (they are already around 6GBs).

In short:

How do I store the last line of the http response into a bash variable?

1
  • Part of the problem is that the last line of your output isn't terminated by a linefeed, which causes read to have a non-zero exit status, thereby skipping the body of the loop. Another issue is the combination of CR/LF line endings with your failure to quote the parameter expansion. Compare echo $output with echo "$output". Commented Feb 22, 2016 at 20:00

1 Answer 1

5

You need to explicitly close the connection in HTTP/1.1:

#!/bin/bash

exec 5<>/dev/tcp/me2stats.eu/5005 # No worries this is a public API ;)

# Send request
printf "GET /gethighscore?level=1 HTTP/1.1\r\n" >&5
printf "Connection:close\r\n" >&5
printf "\r\n" >&5

# Read response. Use tail to retrieve only the last line.
# But be warned! This is dangerous since you won't be able
# to detect HTTP errors any more. (I suggest to use curl!)
response=$(tail -n1 <&5)

echo "$response"

I admit that /dev/tcp is a nice thing to play with, however any more complex tasks, which might require to parse the http response headers carefully, passing passwords, handling cookies but at least if it comes to https (I think this is clear), http communication should be handled with a dedicated http client program like curl or wget.

Here comes an example with curl:

response=$(curl 'me2stats.eu:5005/gethighscore?level=1')

In opposite to the above /dev/tcp script this command only returns the HTTP response body but not the headers. If you are interested in the headers as well use:

response=$(curl -i 'me2stats.eu:5005/gethighscore?level=1')
Sign up to request clarification or add additional context in comments.

7 Comments

@he2mgl, /dev/tcp is not Linux-only; it's a bashism, and doesn't require the kernel to provide any particular functionality that isn't POSIX-standardized; rather, whether it's available is a question of compile-time flags for the shell.
Cool, never knew. So you say it is reliable that where bash is (>4.x.y), there is reliably /dev/tcp - if compiled in? (Even it cygwin?)
Correct, if compiled with ./configure --enable-net-redirections, it'll work even on cygwin.
@CharlesDuffy I've rephrased my answer. Many thanks for that input!
Yah, I went with HTTP 1.0 now and skipped the closing part.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.