read command

read コマンドはファイルを読み出せると今頃知った。
いやまあ、この人と同じようなことをやろうとしたら下のほうに。

sh – IFSに改行のみを指定したい – スタック・オーバーフロー

早速実験コードを書いてみたらあら大変。
アスタリスクが展開されているしインデントが消えている。
運よく C 言語ソースの読み込みで試したおかげで即解った。

bashで * が意図しないワイルドカード展開される場合の対処 – 座敷牢日誌

read だとシェルと同じワイルドカード展開をしてしまうのか。
そういうものだと思うしか無いけど。

readするときはIFS=を付けておくとstrictな感じで気持ちが良い – Qiita

while IFS= なんて手段があったのか!
早速試したけどマジでデフォルトに影響しないんだね。
後で IFS をデフォルトに書き戻す必要が無いってこと。

ということで先頭数文字をオフセットして書き出すスクリプトでも。
ちなみに空行でもスルーしてくれるので文字列長を得る必要は無い。

#!/bin/sh

# 先頭の何文字かをオフセットして出力する bash スクリプト
# [スクリプトファイル名] [オフセットしたい数値] [ファイル名]
# 書き出しはリダイレクトを使う

if [[ $# -lt 2 ]]; then
    echo $0 [オフセットしたい数値] [ファイル名]
else
    while IFS= read -r line; do
        echo "${line:$1}"
    done < $2
fi

# @ for
#_IFS=$IFS
#IFS=$'\n'
#lines=`cat $2`
#for line in $lines; do
#    echo ${line:$1}
#done
#IFS=$_IFS

短っ!

正直スクリプトなんて思ったとおりに動けばそれで充分なんだけどさ。
ココまでスッキリするとチョッピリ嬉しいですね。

Gjs 1.50 GtkWindow

GitHub の gjs サンプルコードが更新されていることに気が付いた。

gjs/gtk-application.js at master ? GNOME/gjs ? GitHub

あれ、_init というメソッドが定義されていたの?
constructor を無理に使わなくてもいいってことみたい。
_init なら以前書いたみたく super() 以降を別関数に分けなくてもイケるのかな。

GtkApplication を使うなら Gtk.init() は不要だった。
実は Y901x を作っていた時に気がついていた、コッチに書くのを忘れていた。

constructor の引数は JSON しか受け付けなかったけど _init だとどうだ?
わかんない時はとっととサンプルコードを書いて動かすほうが速いので早速。
単なる Window ではつまらないので Evince のバインドで。

#!/usr/bin/gjs

imports.gi.versions.Gtk = "3.0";
imports.gi.versions.EvinceDocument = "3.0";
imports.gi.versions.EvinceView = "3.0";

const Gtk = imports.gi.Gtk;
const Gdk = imports.gi.Gdk;
const GObject = imports.gi.GObject;
const EvinceDocument = imports.gi.EvinceDocument;
const EvinceView = imports.gi.EvinceView;

var EvinceWindow = GObject.registerClass({
    GTypeName: "EvinceWindow"
}, class EvinceWindow extends Gtk.Window {
    /*constructor(props={}) {
        super(props);
    }
    create() {*/
    _init(text) {
        super._init({title: text});
        this.model = new EvinceView.DocumentModel();
        let view = new EvinceView.View();
        view.set_model(this.model);
        // Scroll
        let scroll = new Gtk.ScrolledWindow();
        scroll.add(view);
        this.add(scroll);
        /* No need
        this.drag_dest_set(
            Gtk.DestDefaults.MOTION | Gtk.DestDefaults.HIGHLIGHT | Gtk.DestDefaults.DROP,
            [Gtk.TargetEntry.new("text/uri-list", 0, 0)],
            Gdk.DragAction.MOVE
        );*/
        this.drag_dest_add_uri_targets();
        this.connect("drag-data-received", (widget, drag_context, x, y, data, info, time)=> {
            let uri = data.get_uris()[0];
            let doc = EvinceDocument.Document.factory_get_document(uri);
            this.model.set_document(doc);
        });
        //this.connect("hide", Gtk.main_quit); //arguments Error
        this.connect("hide", ()=>Gtk.main_quit());
        this.show_all();
    }
});

// When GtkApplication is not used.
Gtk.init(null);

EvinceDocument.init();

let ev = new EvinceWindow("Drop the PDF File!");
//ev.create();
Gtk.main();

なるほど、_init を使うほうが圧倒的に簡単になるやん。
ちなみに gir で Evince 等を使うドキュメントは以下に。
GNOME JavaScript Docs

それより drag_dest_set 指定はいつのまに不要になったのだ?
以前は drag_dest_add_uri_targets だけでは動作しなかった気がするんだが。

jjs Timer

JavaScript 関連で検索していると大半が
setInterval, setTimeout
を使っているんだけど、これってウエブブラウザと Node.js しか使えない。

Gjs で使う手段は筆者は PyGObject の経験ですぐ解る。
JXA も Objectibe-C から書き換えるだけなので簡単。
問題は jjs だ、情報が無さすぎる。

TimerTask (Java Platform SE 8 )

どうやらこのクラスを使うしかなさそうなんだけど。。。。。
jjs でクラスメソッドのオーバーライドってどうやるんだ?

SOAT Blog ? Java 8 ? What’s new ? ? 3/3 ? Type Annotations et Nashorn

こんなブログ見つけた!
なるほど、コンストラクタの後ろに JSON で指定ね。
なんか変なので括弧の内側に書いても同様に動いた、相変わらずいいかげんな言語だ。
Gjs, JXA と似た感じになるので内側推奨。

サンプルコードを試すと動いたけど Ctrl_C を使わないと終了しないじゃないの。
多分 Timer クラスの cancel メソッドを呼ばないと終了できないんだろう。
sleep を使っているのも気に入らない、書き換えだ。

#!/usr/bin/env jjs

var count = 1;
var timer = new java.util.Timer();
var task = new java.util.TimerTask({
    run: function() {
        if (count == 5) {
            task.cancel();
            timer.cancel();
        }
        print(count);
        count++;
    }
});
timer.schedule(task, 0, 1000);
print("__EOL__");

OK!

どういうわけか timer を task の前に定義しないと動かなかった。
__EOL__ まで抜けているので参照できるはずなんだけど多分仕様だろう。

つか、JXA は全然簡単じゃなかったワイ!
jxa – setTimout with Javascript for automation – Stack Overflow

JXA はなるべく解りやすいよう書き換えて、まとめてみた。
Gjs, jjs, JXA, Node.js – L’Isola di Niente

てなことで。
あけましておめでとうございます。

ES6: Octal number

ES6 では数値リテラルのプリフィクスが追加されていた。
0o で 8 進数、0b で 2 進数ということらしい。
新8進数と2進数の数値リテラルが実装された – JS.next

SpiderMonkey, JavaScriptCore, V8 すべて現行版にて実相済み。

2018 からはコレだね、古いブラウザを完全に駆逐しようぜ!!!
サポートをとっくに終了した IE6 がまだ一部で生き残っていることを筆者は知っている。
死ねよ。

8 進数なんてパーミッションを弄る時くらいしか使わないので気が付かなかった。
ちなみに 076 という表記は SpiderMonkey のみエラーになった。
更に Python3 も同様、いつのまに…

8 進数は英語で Octal number だから o なのか。
2 進数は Binary number、なるほど。
C 言語もこうしてくれよ、076 なんて表記はどう考えてもおかしい。
スマホがメインのウエブブラウザになった時代に 0120 を間違えるとかetc…

また覚書ページを書き換えなきゃ、忙しい正月になりそう。

連番ファイルのダウンロード

とあるサイトの連番ファイルをダウンロードしたくなった。
んで、そんなの bash シェルスクリプトが使える環境 (macOS, Linux) なら超簡単で。

#!/bin/sh

# 001.jpg - 200.jpg だった場合
for (( i=1; i<201; i++ )); do
    n=`printf %03d.jpg $i`
    wget http://なんちゃらどっとこむ/${n}.jpg
done

# 1.jpg - 200.jpg だった場合
#for (( i=1; i<201; i++ )); do
#    wget http://なんちゃらどっとこむ/${i}.jpg
#done

以上。

なんだよこの for 文は使い道があるじゃないの!
wget コマンドは一部ディストリビューションでは dnf や apt で。
google-chrome が使っているから依存関係で勝手に入るはずだけーがさ。

エロゲ専用に落ちぶれた某 OS はアプリや拡張を使うんでしょ?
プログラミングができないサルだけがいまだに使っている OS だよねwwwwww

いや、せっかくだからサイトの JPEG リンク抜き出しをやりたいぞ。
とりあえず URL を読み込んで、それから

href="空白のない文字列jpeg"

を正規表現で抜き出して slice すれば簡単に wget できそうだ。
Python3 の urllib を使えばアホみたく簡単そうだけど、あえて gjs で。

#!/usr/bin/gjs

const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;

if (ARGV.length == 0) {
    print("URL を指定してください");
} else {
    let file = Gio.File.new_for_uri(ARGV[0]);
    let fstream = file.read(null);
    let dstream = new Gio.DataInputStream({base_stream: fstream});
    for (;;) {
        let [val, len] = dstream.read_line_utf8(null);
        if (val.match(/\<\/html\>/gi) !== null)
            break;
        // href="空白のない文字列jpeg" の取得
        let links = val.match(/href=[\'|"]\S+(jpg|jpeg)[\'|"]/gi);
        if (links !== null) {
            for (let link of links) {
                let url = link.slice(6, link.length - 1);
                print(`${url} を取得します`);
                GLib.spawn_command_line_async(`wget ${url}`);
            }
        }
    }
}
//ex: ft=js

書いてみた。

相対パスの場合はガン無視だけど昨今は WordPress ベースが大半だしこれでいいか。
つか相対パスにしている人はそもそも連番ばかりなので最初のでいい。

テキトーなエロ画像サイトで上記を試す。
普通にダウンロードされた、後はリネームして順番を合わせるだけ。
自分が書いたコードが思った通りに動くって本当に面白い。