I'm trying to return a boolean if a curl response has a status of 200.

curl https://www.example.com -I | grep ' 200 ' ? echo '1' : echo '0';

This however brings back:

grep: ?: No such file or directory
grep: echo: No such file or directory
grep: 1: No such file or directory
grep: :: No such file or directory
grep: echo: No such file or directory
grep: 0: No such file or directory
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:--  0:00:01 --:--:--     0

So I'm thinking (and from reading other threads) that grep doesn't support the ternary operator?

Is there a simple one liner to do this without creating a shell script? (also my grep ' 200 ' is loose but I figure I can make that more specific later)

share|improve this question
3  
Possible duplicate of One liner to see if grep returned something? – muru 4 hours ago
    
@muru My question is similiar but the answers on the other questions are more elaborate, and to my question, overkill ( as I see it). – chris85 4 hours ago
    
If you just need to return true if found or false if not found, that is exactly what grep returns ... so : curl ...... -I | grep ' 200 ' >/dev/null ; return "$?" ( in bash, $? (return of the last group of commands) gives the return of the last command executed in the pipe, grep here) . bash or grep don't have the ternary (aka "Elvis" ?: ) operator, but awk does, if you reaaaaally want to use it here. – Olivier Dulac 28 mins ago
up vote 4 down vote accepted

Like a quick study of the grep manual page should reveal, it allows for options, a search pattern (multiple patterns if you specify multiple -e options), and an optional list of file names, falling back to reading standard input like many other Unix filters if no file names are specified. There is nothing about a ternary operator.

If it were supported, it would arguably need to be a feature of the shell, but no shell I know of supports anything like this. It would also clash with the syntax for ? as a wildcard metacharacter which (in isolation) matches any single-character file name.

The usual shorthand idiom in Bourne-compatible shells looks like

curl https://www.example.com/ -I | grep -q ' 200 ' && echo 1 || echo 0

This could accidentally match on a "200" somewhere else in the output. For improved accuracy, try curl https://www.example.com/ -I | head -1 | grep ' 200 ' or perhaps curl https://www.example.com/ -I | awk 'NR==1 { print ($2=="200" ? "1" : "0"); exit }' where the precision of the matching operation is significantly improved.

As an afterthought, if you want to print "0" in the case of invalid URLs and other unexpected errors too, you could set the default output to 0 and change it to 1 when you see 200, then print whatever it ended up as at the end.

curl https://www.example.com/ -I |
awk 'BEGIN { s=0 } NR==1 { s=($2=="200"); exit } END { print s }'
share|improve this answer
    
Yes, this is well written all makes sense. If the domain didn't resolve though would there also be a way to make that fall into the else? I read the || echo 0 as an else maybe this is more of a null coalesce operation though? Current curl failure brings curl: (6) Could not resolve host: www.example.cm; nodename nor servname provided, or not known (tested with example.cm just as edge case) – chris85 5 hours ago
    
Awk is slightly pesky in that if there is no input, there will be no output unless you specifically say so. I'll post an update with slightly different logic. – tripleee 5 hours ago
    
curl https://www.example.com/ -I | awk 'BEGIN { s=1 } NR==1 { s=1-($2=="200"); exit } END { print s } fails, I get 0 when the response is 200. Rough example HTTP/1.1 200 OK Date: Wed, 19 Apr 2017 05:21:22 GMT Server: Apache/2.2.15 (CentOS). – chris85 5 hours ago
    
Sorry, I had 1 and 0 reversed (program exit codes typically use 0 for success). – tripleee 5 hours ago
    
Okay, that looks to be working. Is there a way to return just the 0 on curl resolution failures? – chris85 5 hours ago
! curl https://www.example.com -I | grep -q ' 200 '; echo "$?"
! curl https://www.example.com -I | grep -q ' 200 '; yes "$?" | sed q
share|improve this answer
    
Yes, this works. So shorthand isnt available though? – chris85 5 hours ago
    
@chris85 Modifed the command now. – Rakesh Sharma 5 hours ago

You can use awk to process the output as:

curl https://www.example.com -I | awk '/ 200 /{found=1} END{if (found) print 1; else print 0}'

This sets the variable found to 1 (although anything would work in this case) when the pattern / 200 / is seen. Then when the processing is done, the if tests to see if found has been set and reacts accordingly.

share|improve this answer
    
This also works, could you please add a explanation I haven't seen this awk usage before. Specifically /200/{found=1}. I'd guess if 200 is present found gets set to 1. – chris85 5 hours ago
    
For HTTP(S) headers, you actually want to examine the second field of the first line of the output specifically. The END pattern means you look for a match anywhere in the headers. My answer contains a slightly more focused version which exits after reading the first line. – tripleee 5 hours ago
    
note that this uses curl -I, which uses the HTTP head command. This may not necessarily be the request the writer is expecting and in fact not all webapps implement HEAD . It may be better to use curl -D - -o /dev/null as your output source, then use grep as appropriate to search for the HTTP return code. Or curl -D - -s -o /dev/null https://www.example.com |head -n1 |grep -w '200' – madumlao 5 hours ago
    
And/or maybe just use -w '%{http_code}'. – tripleee 5 hours ago
1  
The answers here should hopefully be general enough to help others in the future too, so the points about servers not supporting HEAD is useful and relevant even if it's out of scope for your immediate problem. – tripleee 4 hours ago

Here's how I might do it:

if [ "x$(curl -Isqw '%{http_code}' -o /dev/null http://example.com/)" = 'x200' ]; then echo "yep"; else echo "nope"; fi

To break it down:

  1. Set the "silent" and "quiet" flags on curl and redirect the actual response to the bit bucket with -o /dev/null. This stops all curl output whatsoever, which lets us focus on our quarry, the status code. (The -I is a courtesy to the server: we are discarding the response anyway, so we request only the headers of the response)
  2. Ask curl to output the response code with the -w '%{http_code}'flag.
  3. Catch all the output in a single string with the "$()"syntax, and prepend the letter x just to make sure there's always something in the string, even if the command crashes and burns (old habits die hard). The proper thing to do would be to check the return code of the curl command at this point, but since any failures now get neatly mapped to a "not 200" result anyway, we won't bother.
  4. Use the [ command (usually found at /bin/[, which is often a symlink to /bin/test) to check if the resulting string is identical to "x200"
  5. Now we already have the boolean value, but since the question asked for a "string boolean", finally use if to choose what to output. The actual syntax for if may vary from one shell to another; this one will work with sh, bash and their relatives.
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.