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}],
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.
    – PowerUp
    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)"
2
  • Charles, how do I write this in Python 2.6.5 without jq?
    – PowerUp
    Commented Mar 28, 2016 at 15:17
  • @Fadiddy, see the extended/amended answer. Commented Mar 28, 2016 at 17:33
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))
2
  • How does jo parse ip -o addr list into fields here? I don't see how it could get the desired output format. Commented Mar 24, 2016 at 20:49
  • 1
    Also, you need more quotes to prevent the shell from string-splitting your key/value pairs before they're passed to jo. Commented Mar 24, 2016 at 20:50

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.