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
  • 280,126
  • 43
  • 390
  • 441
PowerUp
  • 55
  • 1
  • 9
  • 2
    jq -- https://stedolan.github.io/jq/ -- is your friend. – Charles Duffy Mar 24 '16 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`. – Charles Duffy Mar 24 '16 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... – Charles Duffy Mar 24 '16 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 Mar 28 '16 at 13:14
  • Using a language with a built-in JSON module -- such as Python -- is your best bet, then. – Charles Duffy Mar 28 '16 at 14:34

2 Answers2

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)"
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
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))
tschoffelen
  • 518
  • 7
  • 21