まえふり
Windowsには、コマンドプロンプトに送るというツールがあって、ファイルエクスプローラー上のファイルを掴んで右クリックメニューを開き、SendToを通してこのツールへ「送る」と該当ファイルのあるディレクトを起点としてコマンドプロンプトが起動し、ファイル名がターミナルに自動入力される。
このツールはWindows8以降で、おそらくはセキリティの問題から動作しなくなった(または動作するかどうかが「おま環」に左右されるようになった)ため、後に新規に後継ツールを作り直す羽目になった。
できれば、この機能をLinux上でも実現したいと思う。
作戦と方針
プラン1:expect
パスワード入力などの、そのままでは自動化できない処理を自動化するためのツールを利用する案。
これに対する判断を、わかりやすく「総統閣下シリーズ」で説明すると、
震える手で眼鏡を外しながら、
「Wayland時代でもexpectで大丈夫だと思うものだけ残れ」
というセリフになる。
このツールの存在は、現代の喫煙者同様に弱い立場にあるのだ。
プラン2:wezterm
weztermとは、自動入力の機能を持っているターミナルアプリである。マルチプラットフォームであり、Linux,Windows,Macでも動作するため、OS依存度の低い実装が可能になる。
今だにMINTの公式のaptに出てこない(2026年春時点)のが懸念されるが、GitHubからUbuntu22用のバイナリのtar-ballを落としてMINT22/XFCE上で/usr/local/weztermに解凍したところ、PATHを通しただけでばっちり動作した。
結論
weztermでいく。WindowsとLinuxの両方で動作させる。
実装
まず、UbuntuのNautilusもMINT/XFCEのThunarもWindowsのファイルエクスプローラーの「SendTo」に該当する機能を持っている。使い方も同じく特定のディレクトリに起動用のアイコンを設置するだけでよい。
Nautilus
Thunar
次にプロセス間通信は環境変数で行う。OS自体が環境変数でディレクトリパスを指定して動作するようになっているので、セキリティ制限が発動する危険性がなく、ファイル名に使える文字コードの問題が発生する心配もあまりない。
そしてターミナルへの自動入力は外部からでなくシェルのプロファイル側で行うことでリモートアクセスの制限の発動を予防する。具体的には環境変数で受け取ったファイル名をweztermの「send-text」コマンドを通して自動入力することにする。
シナリオ
- デスクトップ環境を通して、対象とするファイルのフルパスを引数としてスクリプトが起動される。
- スクリプトがパス名をディレクトリとファイル名に分ける。
- スクリプトがファイル名を環境変数にセットし、weztermにディレクトリを指定して起動する。
- wiztermの起動時に実行されるシェルのプロファイルが環境変数を見てファイル名を自動入力する。
詳細
本体スクリプト
今回はスクリプト言語にRubyを使用する。別にほかの言語でも実装は可能だが、たとえばPythonなどはランタイム環境が文字エンコーディングの変換を要求してしまう。この変換は多くの環境で部分的に不可逆になることが多く、想定外のトラブルの発生源となるので、システムツールにおいては変換なしでに多言語を扱えるRubyの使用を推奨する。また、Windowsにおいてはインストーラーを経由しないアーカイブの解凍のみで、導入時の環境を変えずに標準の全機能をそのまま使え、削除しても痕跡が残らないパッケージがあるという利点も強調しておきたい。
さて、プログラムの入り口のスクリプトとなる「stwez」を作る。
Explorer(Windows),Nautilus(Linux),Thunar(Linux)のいずれでも、
SendToが実行されたら、ショートカット(Windows)またはランチャ(Linux)に紐づけられたアプリに対して、対象のフルパスを引数として起動が行われる。
なので、引数のフルパスのパスの部分をweztermのコマンドラインで指定として追加し、ファイル名の部分を環境変数(SendToWezterm→STWEZ_ITEMとする)を通して引き渡すスクリプトにする。
#!/usr/bin/ruby
#coding: utf-8
class InputItem < Struct.new(:path, :item)
def initialize(path)
if File.directory?(path) then
self.item = ''
self.path = path
elsif File.file?(path)
self.item = File.basename(path)
self.path = path.slice(0, path.size - self.item.size)
if self.item =~ /\s/ then
self.item = '"' + self.item + '"'
end
else # string
self.item = path
self.path = ''
end
if RUBY_PLATFORM =~ /mingw/ then
# %USERPROFILE%\.ssh\config ->
# <struct InputItem path="C:\\Users\\USER\\.ssh", item="config">
if (self.path.size > 0) && (self.path[-1] == File::ALT_SEPARATOR)
self.path = self.path.slice(0, self.path.size - 1)
end
else
if (self.path.size > 0) && (self.path[-1] == File::SEPARATOR)
self.path = self.path.slice(0, self.path.size - 1)
end
end
end
end
if ARGV.size > 0 then
arg = InputItem.new(ARGV[0])
ENV['STWEZ_ITEM'] = arg.item
if arg.path.size > 0 then
system "wezterm-gui start --cwd \"#{arg.path}\""
else
system "wezterm-gui"
end
else
system "wezterm-gui"
end
先頭の行はマジックラインでLinuxでのみ意味があり、これはvi上で「!!wich ruby」と叩くと自動的に生成され、これの先頭に2文字の「#!」を追加すればOK。
保存先はPATHが掛かっていればどこでもよいが、例を出すなら、Linuxであれば/usr/local/bin、Windowsであれば例えば「C:\BIN」とする。
Linuxの場合はこの後、スクリプトに実行権限を与える(例:chmod ugo+x /usr/local/bin/stwez)。
ショートカットアイコン(or ランチャ)を作る。
・Windows
rubyw.exeという実行ファイルを検索し、これを掴んでから右クリックメニューを開き、「ショートカットの作成」を実行する。このショートカットのプロパティを開き、「rubyw.exe」とある項目の末尾に「 -S stwez」(空白にマイナスエスに空白にstwez)を追加する。次にキーボードの「WIN+R」を押して「名前を指定して実行」を開き、「shell:sendto」と入力してENTERを押すと、「SendTo」のフォルダーが開くので、ここに作られたショートカットアイコンを入れる。
・Linux
エディターを開き、以下のようなテキストを入力する。
[Desktop Entry]
Type=Application
Terminal=false
Name=stwez
Comment=send to wezterm
Exec=/usr/local/bin/stwez "%f"
Icon=/usr/local/wezterm/usr/share/icons/hicolor/128x128/apps/org.wezfurlong.wezterm.png
Path=
StartupNotify=false
アイコンは好みで適当な画像を選ぶ。
そして、ファイル名をstwez.desktopという名前で保存する。
Ubuntuであれば、このファイルを「~/.local/share/applications」の下に移動してから以下のコマンドを叩く。
$ chmod ugo+x ~/.local/share/applications/stwez.desktop
$ update-desktop-database ~/.local/share/applications
MINT/XFCEであれば、このファイルを「~/.local/share/Thunar/sendto」の下に移動してから以下のコマンドを叩く
$ chmod ugo+x ~/.local/share/Thunar/sendto/stwez.desktop
これで、右クリックメニューの項目に「stwez」が追加された。
wezterm.luaに追加する部分(Windowsのみ必要)
まず、Linuxのシェルのプロファイルに該当する機能を追加する。
具体的にはAUTOEXEC.BATというファイルが起動の度に自動実行されるように記述する。
-- 戻り値のconfの要素として追加
default_prog = {
'cmd.exe', '/K', 'autoexec.bat'
},
※レジストリをいじるなどして既に同様の機能が追加済みなら、この処理は不要である。
※環境変数PATHを参照してくれるが、セキリティを気にするならフルパスで記述。
次に、キー割り当てをいじる。
WindowsのCMD.EXEは、自動入力後にカーソルを先頭に戻す動作をするために、HOMEキーを送信する必要があるが、Windows版のweztermのCLIコマンドはHOMEキーを直接送信できないので、bashと同じくHOMEキーの機能をCTRL-Aに割り当てて代用するなどして対処する必要がある。
-- 戻り値のconfの要素として追加
keys = {
{ key = 'a', mods = 'CTRL',
action = wezterm.action.SendKey { key = 'Home', mods = 'NONE' },
},
},
※素のCMD.EXEでなくclinkを併用しているなら、デフォルトで割り当て済みなので、この対処は不要である。
AUTOEXEC.BATに追加する部分(Windows)
IF DEFINED STWEZ_ITEM (
ruby -e "print """#{ENV['STWEZ_ITEM']}\001""""|wezterm cli send-text
SET STWEZ_ITEM=
)
「\001」は前述したwezterm.lua内での割り当て、またはclinkのデフォルトのキーバインドのCTRL-Aで、
これは自動入力した後でカーソルをコマンドライン先頭に移すために付加する。
キーバインドを変更しているならそれに合わせる必要がある。
プロファイルに追加する部分(Linux)
# test -vやunsetと書きたいがbash以外に入れ替えたときに大丈夫か心配
if [ "${STWEZ_ITEM}" != "" ]; then
ruby -e "print \"#{ENV['STWEZ_ITEM']}\\001\\014\""|wezterm cli send-text
STWEZ_ITEM=""
fi
「\001」はbashのデフォルトのキーバインドのCTRL-Aで、
これは自動入力した後でカーソルをコマンドライン先頭に移すために付加する。
キーバインドを変更しているならそれに合わせる必要がある。
「\014」は端末の再描画のCTRL-Lで、表示周りの不具合に対応するために入れた。
原因は不明だが、現時点(2026年春)で画面制御にバグがあり、再描画を入れないと表示が崩れる。これは、先々のアップデート後に不要になるかもしれない。
最後に動作確認
一通りの準備はここで終わったので、動作確認になるが、
Linuxの場合、不具合回避のおまじないとして一度ログアウトしてログインをやり直した方が良い。
無事に動いたらおめでとう。
ペニーワイズ曰く:
ハーイ、ジョージー、
weztermはいいぞ、ジョージー。
オーイエス、
深い… 君も絶対ハマルから…
俺と同じ沼に堕ちろ!
