Here's a simple bash two-liner that will return the status code and content, and work with single or multiple line document bodies.
If we were to run the script below, curl would write the document body followed by the HTTP status code to stdout.
URL="https://superuser.com/questions/1320674/get-response-body-and-show-http-code-by-curl"
curl -s -w "%{http_code}\n" $URL
If we reorder these so the HTTP status code is output first, followed by the document body, we can utilize a feature of the bash builtin read
to stuff all the body into a single shell variable.
man builtins
...
read [-ers] [-a aname] [-d delim] [-i text] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u fd] [name ...]
One line is read from the standard input, or from the file descriptor fd supplied as an argument to the -u option, split into words as described in bash(1) under Word
Splitting, and the first word is assigned to the first name, the second word to the second name, and so on. If there are more words than names, the remaining words and
their intervening delimiters are assigned to the last name. If there are fewer words read from the input stream than names, the remaining names are assigned empty values.
The characters in IFS are used to split the line into words using the same rules the shell uses for expansion (described in bash(1) under Word Splitting). The backslash
character (\) may be used to remove any special meaning for the next character read and for line continuation. Options, if supplied, have the following meanings:
...
Reordering the curl output can be achieved by writing the output to a file. curl will send the information requested by the -w, --write-out
option to stdout first. The file the body is being written to is substituted for a sub process using process substitution >(), with the body sent to this sub process's stdin. Within this sub process, the read
command is used to grab the document body from stdin by using the -u0
option to specify the input stream. IFS=
disables word splitting so whitespace is passed through unchanged. The body is saved to a variable named stdin
, named purely for ease of reference. printf
is used to write the value of this varible to stdout.
IFS=$'\n' read -r -d '' http_status body < <(curl -s -w "%{http_code}\n" -o \
>(IFS= read -r -d '' -u0 stdin; printf "%s" "$stdin") $URL)
Now the data is correctly ordered inside stdout, we use a subsequent process substitution to send it to another read
command in the parent shell process that will place it into shell variables. IFS=$'\n'
sets word splitting to only occur on new lines. The first word is the HTTP status code so this is placed into the http_status
variable. All subsequent words are placed into the body
variable. The -r
option to read
is used to disable backslash escape processing of the document body data. The -d ''
option sets the delimiter to null to ensure read
consumes everything.
echo $http_status
200
echo $body | head -8
<!DOCTYPE html>
<html itemscope itemtype="https://schema.org/QAPage" class="html__responsive " lang="en">
<head>
<title>bash - Get response body and show HTTP code by curl - Super User</title>