Paepoi » JavaScript Tips » Gjs, JXA, Node.js
Gjs, JXA, Node.js
# 最終更新日 2024.03.30
- Node.js 関連を ESM 化、及び promises 仕様に書き換えしました
- 動作確認バージョンを追記しました
スタンドアロン(単独で利用できる)の JavaScript 実行環境での基本機能の覚書
UNIX 系(macOS 含む)のみで動作確認
- Node.js 関連を ESM 化、及び promises 仕様に書き換えしました
- 動作確認バージョンを追記しました
スタンドアロン(単独で利用できる)の JavaScript 実行環境での基本機能の覚書
UNIX 系(macOS 含む)のみで動作確認
通称 | コマンド名 | 動作環境 | コア | 動作確認 |
---|---|---|---|---|
Gjs | gjs | GNOME | SpiderMonkey | 1.78 |
JXA | osascript | macOS | JavaScriptCore | 10.11(放置) |
Node.js | node | マルチ | V8 | 20.01 |
標準入出力
echo ほげ | gjs test.js のようなパイプ入力にも対応
/** * Gjs (gjs コマンドに -m オプションが必要) */ import GLib from 'gi://GLib'; // readline は自作 let readline = function(prpt) { // stdin=0 stdout=1 let channel = GLib.IOChannel.unix_new(0); let stdin = '端末入力'; if (channel.get_flags() == GLib.IOFlags.IS_READABLE) { stdin = 'パイプ'; } else { channel.write_chars(prpt, -1); } let [status, str_return] = channel.read_line(); let line = str_return.trimEnd(); return [stdin, line]; } let [stdin, line] = readline('何か入力して Enter :'); console.log(`${stdin}から ${line} が渡されました`); /** * JXA (GNU readline 同様に使える) */ ObjC.import('readline'); ObjC.import('unistd'); let prefix = $.isatty(0) ? '端末入力' : 'パイプ'; let line = $.readline('何か入力して return :'); console.log(`${prefix}から ${line} が渡されました`); /** * Node.js (拡張子を *.mjs にする必要があります) */ import * as readline from 'node:readline/promises'; import * as tty from 'node:tty'; import { stdin as input, stdout as output } from 'node:process'; let rl = readline.createInterface({ input, output, terminal:false }); let [prpt, prefix] = tty.isatty(0) ? ['何か入力して return :', '端末入力'] : ['', 'パイプ']; let line = await rl.question(prpt); console.log(`${prefix}から ${line} が渡されました`); rl.close();
ファイルの読み書き
Gjs は Gio を使ったほうがいいけどそれは別のページにて
/** * Gjs */ import GLib from 'gi://GLib'; const FILE = 'write_gjs.txt'; const TEXT = `出力では JavaScript 文字列のままイケます 入力は Uint8Array になりますので以下のように`; let result = GLib.file_set_contents(FILE, TEXT); // Write if (result) { console.log('Write Success'); } let [result2, contents] = GLib.file_get_contents(FILE); // Read if (result2) { let dec = new TextDecoder(); let text = dec.decode(contents); console.log(text); } /** * JXA */ ObjC.import('Cocoa'); const FILE = $('write_jxa.txt'); const TEXT = $('日本語を書き込むよ\n改行もしてみるよ'); let nil = $(); // Write let res = TEXT.writeToFileAtomicallyEncodingError(FILE, true, $.NSUTF8StringEncoding, nil); if (res) { console.log('Write Success!'); } // Read let s = $.NSString.alloc.initWithContentsOfFileEncodingError(FILE, $.NSUTF8StringEncoding, nil); console.log(s.js); /** * Node.js */ import fs from 'node:fs/promises'; const FILE = 'write_node.txt'; const TEXT = '日本語を書き込むよ\n改行もしてみるよ'; try { await fs.writeFile(FILE, TEXT); console.log('Write Success!'); } catch(err) { console.log(err); } try { let content = await fs.readFile(FILE, 'utf8') console.log(content.trim()); } catch(err) { console.log(err); }
起動パラメータ
Node.js はシェルそのままなパラメータになる、他は全部引数のみの配列
/** * Gjs (1.52 からUNICODE 化されました) */ if (ARGV.length == 0) { console.log('No argv'); } else { for (let s of ARGV) { console.log(s) } } /** * JXA */ function run(argv) { if (argv.length == 0) { console.log('No argv'); } else { for (let s of argv) { console.log(s); } } } /** * Node.js (実行ファイル名, スクリプトファイル名, argv[0], argv[1], ...) */ if (process.argv.length < 3) { console.log('No argv'); } else { for (let s of process.argv) { console.log(s); } }
環境変数
$HOME を表示する例
/** * Gjs */ import GLib from 'gi://GLib'; console.log(GLib.getenv('HOME')); /** * JXA */ ObjC.import('stdlib'); console.log($.getenv('HOME')); /** * Node.js */ console.log(process.env.HOME);
シェルコマンドの実行
ls -l の結果を得て表示する例
/** * Gjs */ import GLib from 'gi://GLib'; let output = GLib.spawn_command_line_sync('ls -l')[1]; let dec = new TextDecoder(); let text = dec.decode(output); console.log(text); /** * JXA */ let app = Application.currentApplication(); app.includeStandardAdditions = true; // alteringLineEndings オプション無しだと改行が CR に変換される let res = app.doShellScript('ls -l', {alteringLineEndings: false}); console.log(res); /** * Node.js */ import {exec} from 'node:child_process'; exec('ls -l', (err, stdout, stderr)=> { console.log(stdout); });
タイマー
setInterval, setTimeout は Gjs でも使えるようになりました
/** * Gjs (メインループが必要) */ import GLib from 'gi://GLib'; const mainloop = new GLib.MainLoop(null, false); let count = 1; let id = setInterval(()=> { if (count == 5) { clearInterval(id); mainloop.quit(); } console.log(count); count++; }, 1000); mainloop.run(); /** * JXA */ ObjC.import('Cocoa'); let count = 1; let operation = $.NSBlockOperation.blockOperationWithBlock(()=> { if (count == 5) timer.invalidate; console.log(count); count++; }); let timer = $.NSTimer.timerWithTimeIntervalTargetSelectorUserInfoRepeats( 1, operation, 'main', null, true); $.NSRunLoop.currentRunLoop.addTimerForMode(timer, 'timer'); // 戻り値が表示されないよう変数に入れる let r = $.NSRunLoop.currentRunLoop.runModeBeforeDate('timer', $.NSDate.distantFuture); /** * Node.js (ブラウザと同じ、メインループは node がやってくれる) */ let count = 1; let id = setInterval(()=> { if (count == 5) clearInterval(id); console.log(count); count++; }, 1000);
Copyright(C) sasakima-nao All rights reserved 2002 --- 2024.