user1901162
user1901162

Reputation: 1027

How to grep from a single line

I'm using a weather API that outputs all data in a single line. How do I use grep to get the values for "summary" and "apparentTemperature"? My command of regular expressions is basically nonexistent, but I'm ready to learn.

{"latitude":59.433335,"longitude":24.750486,"timezone":"Europe/Tallinn","offset":2,"currently":{"time":1485880052,"summary":"Clear","icon":"clear-night","precipIntensity":0,"precipProbability":0,"temperature":0.76,"apparentTemperature":-3.34,"dewPoint":-0.13,"humidity":0.94,"windSpeed":3.99,"windBearing":262,"visibility":9.99,"cloudCover":0.11,"pressure":1017.72,"ozone":282.98}}

Thank you!

Upvotes: 5

Views: 13372

Answers (4)

Amit Naidu
Amit Naidu

Reputation: 2648

As Aaron mentioned a json parser like jq is the right tool for this, but since the question was about grep, let's see one way to do it.

Assuming your API return value is in $json:

json='{"latitude":59.433335,"longitude":24.750486,"timezone":"Europe/Tallinn","offset":2,"currently":{"time":1485880052,"summary":"Clear","icon":"clear-night","precipIntensity":0,"precipProbability":0,"temperature":0.76,"apparentTemperature":-3.34,"dewPoint":-0.13,"humidity":0.94,"windSpeed":3.99,"windBearing":262,"visibility":9.99,"cloudCover":0.11,"pressure":1017.72,"ozone":282.98}}'

The patterns you see in the parenthesis are lookbehind and lookahead assertions for context matching. They can be used with the -P Perl regex option and will not be captured in the output.

summary=$(<<< "$json" grep -oP '(?<="summary":").*?(?=",)')
apparentTemperature=$(<<< "$json" grep -oP '(?<="apparentTemperature":).*?(?=,)')

Upvotes: -1

Mark Setchell
Mark Setchell

Reputation: 207668

This is fairly easily understood if your skills are limited - like mine! Assuming your string is in a variable called $LINE:

summary=$(sed -e 's/.*summary":"//'  -e 's/".*//' <<< $LINE)

Then check:

echo $summary
Clear

That executes (-e) 2 sed commands. The first one substitutes everything up to summary":" with nothing and the second substitutes the first remaining double quote and everything that follows with nothing.

Extract apparent temperature:

appTemp=$(sed -e 's/.*apparentTemperature"://'  -e 's/,.*//' <<< $LINE)

Then check:

echo $appTemp
-3.34

Upvotes: 0

Fred
Fred

Reputation: 6995

Assume your single-line data is contained in a variable called DATA_LINE.

If you are certain the field is only present once in the whole line, you could do something like this in Bash:

if
  [[ "$DATA_LINE" =~ \"summary\":\"([^\"]*)\" ]]
then
  summary="${BASH_REMATCH[1]}"
  echo "Summary field is : $summary"
else
  echo "Summary field not found"
fi

You would have to do that once for each field, unless you build a more complex matching expression that assumes fields are in a specific order.

As a note, the matching expression \"summary\":\"([^\"]*)\" finds the first occurrence in the data of a substring consisting of :

  • "summary":" (double quotes included), followed by
  • ([^\"]*) a sub-expression formed of a sequence of zero or more characters other than a double quote : this is in parentheses to make it available later as an element in the BASH_REMATCH array, because this is the value you want to extract
  • and finally a final quote ; this is not absolutely necessary, but protects from reading from a truncated data line.

For apparentTemperature the code will be a bit different because the field does not have the same format.

if
  [[ "$DATA_LINE" =~ \"apparentTemperature\":([^,]*), ]]
then
  apparentTemperature="${BASH_REMATCH[1]}"
  echo "Apparent temperature field is : $apparentTemperature"
else
  echo "Apparent temperature field  not found"
fi

Upvotes: 2

Aaron
Aaron

Reputation: 24812

How do I use grep to get the values for "summary" and "apparentTemperature"?

You use grep's -o flag, which makes it output only the matched part.

Since you don't know much about regex, I suggest you instead learn to use a JSON parser, which would be more appropriate for this task.

For example with jq, the following command would extract the current summary :

<whatever is your JSON source> | jq '.currently.summary'

Upvotes: 6

Related Questions