問題
ls
の出力結果をJSON配列にしたいとします。たとえば、
$ ls
bin games include lib lib32 lib64 libexec libx32 local sbin share src
から、
["bin", "games", "include", ..., "src"]
を生成するわけです。
jq
を使う
いろいろ試してみましたが、コマンドライン志向のJSONパーザーであるjq
を使うのが一番楽でしょう。こうです。
$ ls | jq -Rsc 'split("\n")[0:-1]'
["bin","games","include","lib","lib32","lib64","libexec","libx32","local","sbin","share","src"]
配列化してしまえば、要素単位の処理は簡単です。たとえば、ファイル/ディレクトリ名を項目にしたHTMLリスト(<li></li>
)を作成するなら、こうします。
$ ls | jq -Rsr 'split("\n")[0:-1] | map("<li>" + . + "</li>")[]'
<li>bin</li>
<li>games</li>
...
<li>share</li>
<li>src</li>
解題
ls
のファイル名は二重引用符で囲まれていないので、JSON文字列としては文法違反です。そこで、-R
オプション(ロングフォーマットは--raw-input
)を使って、強制的に文字列として読み込ませます。
$ ls | jq -R '.'
"bin"
"games"
...
"share"
"src"
この結果では、各ファイル名がそれぞれ独立したJSONテキストとして扱われます。配列化するにはこれらをひとまとめにしなければなりません。それには-s
(--slurp
)を使います。複数のテキストが入力されたら、それらを1つの大きな文字列として扱えという指示です。
$ ls | jq -Rs '.'
"bin\ngames\ninclude\nlib\nlib32\nlib64\nlibexec\nlibx32\nlocal\nsbin\nshare\nsrc\n"
ばらばらだった行が\n
をデリミタに連結されました。あとは、これをsplit
で分解し、配列にします。
$ ls | jq -Rs 'split("\n")'
[
"bin",
"games",
...
"share",
"src",
"" # ここ余分
]
末尾に空文字の要素があります。これは、最後の行の改行コード("src\n"
)の次の文字を指しています。不要なので、末尾の要素はスライスで取り除きます(形式はPythonとかでおなじみです)。
$ ls | jq -Rs 'split("\n")[0:-1]'
[
"bin",
"games",
...
"share",
"src"
]
コマンドオプションに-c
(--compact-output
)を加えると、横1列に出力してくれます。ま、見栄えの話です。
$ ls | jq -Rsc 'split("\n")[0:-1]'
["bin","games","include","lib","lib32","lib64","libexec","libx32","local","sbin","share","src"]
おわりに
最初はawk
を使ってみましたが、最後のカンマが面倒で途中で挫折しました。if
とか入れるとややこしくなるし...
$ ls | awk 'BEGIN {print "["} {print "\""$0"\","} END{print "]"}'
[
"bin",
"games",
...
"share",
"src", # あああ、これが。
]
readarray
とかも考えたけど、これもループを組むのが面倒なので、やっぱり挫折しました。イテレータが使えるjq
はやっぱりこういうときに便利です。