0

I'm new to Linux and Bash scripting. I am trying to output several bash scripts in Ubuntu Linux into JSON format, however, I cannot seem to get it to work properly.

My goal is to get this:

date -u +%Y-%m-%d:%H:%M:%S //date and time
lsb_release -a //os distro version
ifconfig -a //ip info

Into this format in JSON:

 "datetime":datetime_string,
 "osversion":string,
 "ip_info: [{"interface":string,"ip_addr":string,"mask":string,"gateway":string},
 {"interface":string,"ip_addr":string,"mask":string,"gateway":string}],
Charles Duffy
299k43 gold badges438 silver badges494 bronze badges
asked Mar 24, 2016 at 20:34
5
  • 2
    jq -- stedolan.github.io/jq -- is your friend. Commented Mar 24, 2016 at 20:36
  • 3
    Also, don't use ifconfig; it's an ancient tool nobody has maintained in over a decade. If you want to list IPs on Linux in a way that works with new and modern parts of the network stack, use ip -o addr list. Commented Mar 24, 2016 at 20:39
  • ...btw, gateway isn't present in the output of ifconfig -a. Since the routing table isn't interface-specific, one wouldn't really expect them to be stored/managed together... Commented Mar 24, 2016 at 20:55
  • Charles, how can I output that format without having to install additional packages on the distro? I am trying to avoid having to install additional packages as much as possible. Commented Mar 28, 2016 at 13:14
  • Using a language with a built-in JSON module -- such as Python -- is your best bet, then. Commented Mar 28, 2016 at 14:34

2 Answers 2

3

Bash itself has no JSON support. Thus, to guarantee conformance, you need to use an external utility with JSON parsing and generation support built in. jq is one of these, and the below uses its built-in regex support:

jq --raw-input \
 --arg date "$(date)" \
 --arg osver "$(lsb_release -a)" \
 '{"date": $date,
 "osver": $osver,
 "ip_info": [inputs |
 capture("^[0-9]+: (?<ifname>[^[:space:]]+)[[:space:]]+inet (?<addr>[^[:space:]/]+)(/(?<masklen>[[:digit:]]+))?")
 ]
 }' \
 < <(ip -o addr list | grep 'inet ')

See this code in action on JQPlay.


If you can't install tools not built into your Linux distro, consider Python:

#!/bin/bash
# ^^^^ - important, not /bin/sh; this uses some bash-only syntax
py_code=$(cat <<'EOF'
import json, re, sys
content={'ip_info': []}
for k, v in [ arg.split('=', 1) for arg in sys.argv[2:] if '=' in arg ]:
 content[k]=v
ip_re = re.compile(r'^[0-9]+:\s+(?P<ifname>\S+)\s+inet (?P<addr>[^/\s]+)(?:/(?P<masklen>\d+))?')
for line in open(sys.argv[1]).readlines():
 m = ip_re.match(line)
 if not m: raise "NOOOO"
 content['ip_info'].append({
 'ifname': m.groups('ifname'),
 'addr': m.groups('addr'),
 'masklen': m.groups('masklen'),
 })
print json.dumps(content)
EOF
)
python -c "$py_code" \
 <(ip -o addr list | grep 'inet ') \
 "date=$(date)" "osver=$(lsb_release -a)"
answered Mar 24, 2016 at 20:49
Sign up to request clarification or add additional context in comments.

2 Comments

Charles, how do I write this in Python 2.6.5 without jq?
@Fadiddy, see the extended/amended answer.
0

Something like that should be quite easy to do with jo:

jo datetime=$(date -u +%Y-%m-%d:%H:%M:%S) osversion=$(lsb_release -a) ip_info=$(jo -a $(ip -o addr list))
answered Mar 24, 2016 at 20:46

2 Comments

How does jo parse ip -o addr list into fields here? I don't see how it could get the desired output format.
Also, you need more quotes to prevent the shell from string-splitting your key/value pairs before they're passed to jo.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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.