opyの便利な使い方集

Thu Jul 1 15:53:35 JST 2021 (modified: Sat Jul 3 09:16:33 JST 2021)
views: 1339, keywords: この記事は最終更新日が2年以上前のものです。

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]mn列目のデータが取得できます。mnは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
   危険シェル芸
ノート   このエントリーをはてなブックマークに追加 
 

やり散らかし一覧

記事いろいろ