ushumpei’s blog

生活で気になったことを随時調べて書いていきます。

Deno で簡単な重複行削除スクリプトを書いた

ファイルの重複行削除がしたかったのでスクリプトを書こうと思ったのですが、せっかくだし Deno で書いてみることにしました。

https://github.com/ushumpei/scripts/blob/main/remove_duplicate_lines.ts

import { iter } from "https://deno.land/std@0.93.0/io/util.ts";

const N = Deno.env.get("NEWLINE") || "\n";
export type M = {
  b: boolean;
  d: string[];
  h: { [k: string]: boolean };
};

const i = Deno.args[0];
const o = Deno.args[1];

const f: Deno.File = Deno.openSync(i, { read: true });
const m: M = { d: [], h: {}, b: false };
const t: string = await Deno.makeTempFile();

let r = "";
for await (const ck of iter(f)) {
  const ls = (r + new TextDecoder().decode(ck)).split(N);
  r = ls[ls.length - 1];

  const ot = ls
    .slice(0, -1)
    .reduce((_m: M, l: string) => {
      if (!_m.h[l]) {
        _m.h[l] = true;
        _m.d.push(l);
      }
      return _m;
    }, m)
    .d.join(N);
  if (ot.length === 0) continue;

  const of = new TextEncoder().encode(m.b ? N + ot : ot);
  Deno.writeFileSync(t, of, { append: true });

  m.d = [];
  m.b = true;
}
f.close();

Deno.copyFileSync(t, o);

github にあげていて、こんな感じで URL 指定でも実行できます。

$ deno run --allow-env --allow-read --allow-write \
> https://raw.githubusercontent.com/ushumpei/scripts/main/remove_duplicate_lines.ts \
> 入力ファイル名 \
> 出力ファイル名

感想

  • groovy のようにライブラリのインポート含めてスクリプトが一枚のファイルで完結するので、結構楽でいいです。しかも URL 指定でインポートできるのでより手軽。なので書くときにインポートするものをちゃんと精査しないといけないと思います。 --allow-net などオプションで権限が指定できるので、その辺もしっかり吟味していきたいです。(権限つけ忘れた時のエラー文がわかりやすいのも良い感じ)
  • 書いたスクリプトで宣言している変数名は一文字とかばかりなのですが、なんかテンション上がって極力短くしてみました。楽しかった。
  • 環境変数による改行コードの指定は未テストで、いらないんじゃないかなーと思っています。--allow-env も消せるしそうしたい気がしてきた。
  • メモリに一気に乗せないように書いたつもりだけどどうなんだろう。
    • 既出行を格納しているオブジェクトが巨大になって死ぬとかありそう。
    • あと copyFileSync は中身をみていないけどちょろちょろコピーしてくれるのだろうか?
    • あとこれ TransformStream で描き直したい。
  • Denovscode 拡張入れた後上手く設定できてなくて cannot find name Deno とか言われてたけどコマンドパレットから Deno: Initialize Workspace Configuration 実行したらなんか上手くいった。
  • 無限インポートループとかどうなるんだろうか。
  • https://doc.deno.land/builtin/stable 見て書いた。
  • Deno Deploy はまだちゃんと触っていない、リクエスト処理は fetch イベントのハンドラー書いてやるみたいだけど、ローカルだと発火しなくてちょっと手間取った、なんか公開してくださっているライブラリ入れたら動いた。https://deno.land/x/fetch_event_adapter/listen.ts