opyの便利な使い方集
Thu Jul 1 15:53:35 JST 2021 (modified: Sat Jul 3 09:16:33 JST 2021)
views: 1667, keywords: この記事は最終更新日が3年以上前のものです。
opyって何?
opyは、ワンライナーでPythonを使うためのラッパーコマンドです。
電卓として使う
eval
で文字列を評価するとできます。
echo '2**10' | opy '[eval(F0)]'
$ 1024
echo 'math.cos(math.pi)' | opy '[eval(F0)]'
$ -1.0
若干補足すると、F0
には、毎行読み込んだ文字列が入ります。[ ]
はPythonのリストで、リストの中に処理を書いておくと、上の例のように処理結果がprintされます。math
は自動でimport
されます。
基数変換(n進数→m進数)
n進数→10進数
接頭辞がついていれば、内部で自動的に整数に変換され、print
すると10進数で表示されます。
echo 0b11 | opy '[F1]'
$ 3
echo 0o10 | opy '[F1]'
$ 8
echo 0x10 | opy '[F1]'
$ 16
補足: F1
は読み込んだ行の1列目の文字列が入ります。文字列が数字として解釈できる場合、自動的に数字に変換されます。
接頭語がなければ、つけてから処理しましょう。(sed
でやるべきですが。)
echo aaaaaaaaaa | opy '["0x"+F1]' | opy '[F1]'
$ 733007751850
10進数→n進数
echo 16 | opy '[bin(F1)]'
$ 0b10000
echo 16 | opy '[oct(F1)]'
$ 0o20
echo 16 | opy '[hex(F1)]'
$ 0x10
n進数→m進数
上のふたつのパターンの組み合わせです。
echo 0x10 | opy '[oct(F1)]'
$ 0o20
YAML/JSON/XML形式のデータの読み込み/編集
いずれも、入力全体を読み込んでパースし、辞書T
にセットします。次は、JSONの処理の例です。
### 処理するJSONデータ ###
curl -s https://file.ueda.tech/eki/p/13.json
$ "line":[{"line_cd":11301,"line_name":"JR東海道本線(東京~熱海)"},{"line_cd":11302,"line_name":"JR山手線"},(以下略)
{### Tをリストに入れると全部出力できる ###
curl -s https://file.ueda.tech/eki/p/13.json | opy -t json '[T]'
'line': [{'line_cd': 11301, 'line_name': 'JR東海道本線(東京~熱海)'},(以下略)
{### 要素の参照 ###
curl -s https://file.ueda.tech/eki/p/13.json | opy -t json '[T["line"][0]]'
$ 'line_cd': 11301, 'line_name': 'JR東海道本線(東京~熱海)'}
{### 路線のリストを出力する例 ###
curl -s https://file.ueda.tech/eki/p/13.json | opy -t json '[e["line_name"] for e in T["line"]]'
$ JR東海道本線(東京~熱海)
JR山手線
JR南武線
JR武蔵野線
JR横浜線
・・・
YAMLの例です。
cat ~/tmp/hoge.yml
$ aho:
boke: ["a","b"]
### ahoの下のbokeの配列の0から数えて1番目の要素を取り出す ###
cat ~/tmp/hoge.yml | opy -t yaml '[T["aho"]["boke"][1]]'
$ b
### 改竄して出力 ###
cat ~/tmp/hoge.yml | opy -t yaml '{T["aho"]["boke"][1]="KAIZAN"};[yaml.dump(T)]'
$ aho:
boke:
- a
- KAIZAN
XMLの例です。xml.etree.ElementTree
を使っており、JSONやYAMLの場合とは少し扱いが異なります。
### Tにはオブジェクトが入っている ###
curl -s https://file.ueda.tech/eki/p/13.xml | opy -t xml '[e for e in T]'
$ <Element 'pref' at 0x7fcea5286720>
<Element 'line' at 0x7fcea5286810>
<Element 'line' at 0x7fcea5286900>
・・・### lineのタグを持つ要素だけ抽出 ###
curl -s https://file.ueda.tech/eki/p/13.xml | opy -t xml '[e for e in T if e.tag == "line"]'
$ <Element 'line' at 0x7fb1cb4347c0>
<Element 'line' at 0x7fb1cb4348b0>
<Element 'line' at 0x7fb1cb4349a0>
・・・### 要素の内容を取り出す(名前でなく数字で要素を指定する) ###
curl -s https://file.ueda.tech/eki/p/13.xml | opy -t xml '[e[1].text for e in T if e.tag == "line"]'
$ JR東海道本線(東京~熱海)
JR山手線
JR南武線
・・・
CSVファイルを扱う
ふたつ方法があります。
毎行処理する
-c
を使います。
$ echo 'a,b,c' | opy -c '[F2]'
b
### エスケープだらけでも大丈夫 ###
$ echo 'a,"""b,,,,""""",c' | opy -c '[F2]'
"b,,,,""
この方法は、データの中に改行がある場合には使えません。
$ echo -e 'a,"b\nc",d'
a,"b <-「b改行c」がひとかたまりのデータ
c",d
$ echo -e 'a,"b\nc",d' | opy -c '[F2]'
b
d <-ここはcと出なければならないが、出てこない
全体を読んで処理する
-t csv
を使います。T[m][n]
でm
行n
列目のデータが取得できます。m
、n
は0から始まります。
$ echo -e 'a,"b\nc",d'
a,"b <- -cでは扱えなかったデータ
c",d
$ echo -e 'a,"b\nc",d' | opy -t csv '[T]'
{0: ['a', 'b\nc', 'd']} <- 改行がデータの一部として認識されている
$ echo -e 'a,"b\nc",d' | opy -t csv '[T[0][1]]' <- 0行1列目を出力
b
c <- -cのときと異なり、「b改行c」がデータとして出力される
### 改行を別の文字に置き換える例 ###
$ echo -e 'a,"b\nc",d' | opy -t csv '[T[0][1].replace("\n","@")]'
b@c
XLSXファイルを扱う
-t xlsx
で、PandasのデータフレームがT
にセットされます。標準入力からデータを流し込むのではなく、ファイル名を引数に指定して使ってください。
シートの出力
シートはT["名前"]
で取り出します。
### Sheet1のデータフレームをaという2次元のリストに変換 ###
$ opy -t xlsx '{a = T["Sheet1"].values};[a]' ./testdata/test.xlsx
[[123 datetime.datetime(2021, 1, 1, 0, 0) nan]
['危険シェル芸' 'ドラゴン曲線' nan]
['キュアエンジニア' '素数' nan]
['エ"ク"シ"ェ"ル"芸' '変,態,シ,ェ,ル,芸' nan]
[1 2 3.0]
[nan nan nan]]
### リストに変換しない場合、1行目と1列目に、それぞれ列、行のラベルがつく ###
$ opy -t xlsx '[T["Sheet1"].to_csv()]' ./testdata/test.xlsx
,0,1,2
0,123,2021-01-01 00:00:00,
1,危険シェル芸,ドラゴン曲線,
2,キュアエンジニア,素数,
3,"エ""ク""シ""ェ""ル""芸","変,態,シ,ェ,ル,芸",
4,1,2,3.0
5,,,
1個のセルの内容の抜き出し
データフレームからのデータを取り出すときは、列を先に指定することに注意しましょう。
### 左上(A1)のデータを取り出す ###
$ opy -t xlsx '[T["Sheet1"][0][0]]' ./testdata/test.xlsx
123
### A2(0列1行目)のデータを取り出す。列を先に指定 ###
$ opy -t xlsx '[T["Sheet1"][0][1]]' ./testdata/test.xlsx
危険シェル芸
### リストに変換した場合は行を先に指定 ###
$ opy -t xlsx '{a = T["Sheet1"].values};[a[1][0]]' ./testdata/test.xlsx
危険シェル芸