LoginSignup
0

More than 1 year has passed since last update.

LibXoが組み込まれたコマンドで出力をJSON/XML変換してみる

Last updated at Posted at 2021-12-01

FreeBSD Advent Calendar 2021 2日目の記事です。
今日はFreeBSD-11からサポートされている、LibXoの紹介をしようと思います。

LibXoとは?

LibXoはFreeBSD-11以降でサポートされた、任意のデータをテキスト、XML、JSON、HTMLの各フォーマットで出力するライブラリです。アプリケーション側がLibXoでの出力に対応していれば、ユーザ側は自分の扱いやすいフォーマットでデータを処理することが可能になります。

ドキュメントやソースコードは以下のURLで公開されています。GitHubリポジトリを見ると、どうやらJuniperによりメンテナンスされているライブラリのようですね。

LibXoが組み込まれているコマンド

wcコマンドでの例

FreeBSDでは、ベースコマンドのいくつかにLibXoが組み込まれています。例えば、wc(1)では以下のような形でコマンドの出力を柔軟に変換できます。

$ cat /etc/os-release
NAME=FreeBSD
VERSION=13.0-RELEASE
VERSION_ID=13.0
ID=freebsd
ANSI_COLOR="0;31"
PRETTY_NAME="FreeBSD 13.0-RELEASE"
CPE_NAME=cpe:/o:freebsd:freebsd:13.0
HOME_URL=https://FreeBSD.org/
BUG_REPORT_URL=https://bugs.FreeBSD.org/
$
$ cat /etc/os-release | wc
       9      10     222

wc コマンドに --libxo json,pretty を指定するとJSONフォーマット、 --libxo xml,pretty でXMLフォーマットでの出力になります。

$ cat /etc/os-release | wc --libxo json,pretty
{
  "wc": {
    "file": [
      {
        "lines": 9,
        "words": 10,
        "characters": 222
      }
    ]
  }
}
$
$ cat /etc/os-release | wc --libxo xml,pretty
<wc>
  <file>
    <lines>9</lines>
    <words>10</words>
    <characters>222</characters>
  </file>
</wc>

libxoが組み込まれているコマンド

ldd wc で参照しているライブラリを確認してみると、 /lib/libxo.so.0 を参照していることが分かります。おそらくこのライブラリを参照しているコマンドは --libxo json,pretty のような指定が可能になっているのでしょう。

$ ldd `which wc`
/usr/bin/wc:
        libxo.so.0 => /lib/libxo.so.0 (0x20444000)
        libcasper.so.1 => /lib/libcasper.so.1 (0x20462000)
        libcap_fileargs.so.1 => /lib/casper/libcap_fileargs.so.1 (0x2046a000)
        libc.so.7 => /lib/libc.so.7 (0x20470000)
        libutil.so.9 => /lib/libutil.so.9 (0x20640000)
        libnv.so.0 => /lib/libnv.so.0 (0x20656000)

簡単なスクリプトで /lib/libxo.so.0 を参照しているコマンドを抽出してみます。

for i in `echo $PATH | sed -e "s/:/ /g"`
do
  for j in `find $i -type f`
  do
    echo "===> $j"
    ldd $j
  done
done \
| egrep '^===>|libxo' \
| grep -B1 libxo \
| grep '^===>'

以下のコマンドが該当するようです。

===> /bin/df
===> /bin/ps
===> /sbin/savecore
===> /usr/bin/netstat
===> /usr/bin/w
===> /usr/bin/penv
===> /usr/bin/last
===> /usr/bin/xo
===> /usr/bin/pwdx
===> /usr/bin/pargs
===> /usr/bin/uptime
===> /usr/bin/iscsictl
===> /usr/bin/nfsstat
===> /usr/bin/vmstat
===> /usr/bin/procstat
===> /usr/bin/wc
===> /usr/sbin/lastlogin
===> /usr/sbin/sesutil
===> /usr/sbin/jls
===> /usr/sbin/arp

psコマンドでのサンプル

/lib/libxo.so.0 を参照しているコマンドには、 ps コマンドもあり、より実用的な利用例を示せそうです。
(個人的には jls でも --libxo json,pretty が利用できるのは嬉しい感じです)

$ ps ax --libxo json,pretty
{
  "process-information": {
    "process": [
      {
        "pid": "2467",
        "terminal-name": "- ",
        "state": "IsJ",
        "cpu-time": "0:08.29",
        "command": "/usr/sbin/syslogd -s"
      },
      {
        "pid": "2549",
        "terminal-name": "- ",
        "state": "IsJ",
        "cpu-time": "0:00.08",
        "command": "/usr/sbin/sshd"
      },
...

ps ax --libxo json,pretty での出力を jq コマンド+JSONPathで欲しい項目のみ抽出することが可能になります。
(少なくともシェルスクリプトで細々と文字列処理するよりは楽な感じですね)

$ ps ax --libxo json,pretty | jq -r '."process-information".process[] | select(.command | startswith("vim"))'
{
  "pid": "48072",
  "terminal-name": "12 ",
  "state": "TJ",
  "cpu-time": "0:00.10",
  "command": "vim -R wc.c"
}
$
$ ps ax --libxo json,pretty | jq -r '."process-information".process[] | select(.command | startswith("vim")) | .pid, .command'
48072
vim -R wc.c

まとめ

FreeBSD-11からサポートされた、LibXoについて紹介しました。
ベースコマンドのいくつかはLibXoを組み込んだ状態で提供されており、 --libxo json,pretty のような指定でJSON,XML等の任意の形式で出力を得られます。JSONやXMLは jqxmllint 等でのパースや条件にマッチする項目の抽出が柔軟に行えるため、シェルスクリプトにおける可読性やメンテナンス性の向上に役立ちそうです。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0