Finderで何かしらの操作をしていて、途中でそこのファイルをターミナルから操作したくなる時がある。例えばそれをlessで見たいとする。そんな時はターミナルを開いて
$ less 目的ファイルのフルパス
とやるわけだが、このパスを入力するのは面倒なので、例えばターミナルウィンドウの上に目的のファイルをドラッグアンドドロップすると、ターミナルにパスが入力できる。
でもまあ、それもまだ面倒なので、ターミナル上で、「Finderで現在選択中のパス」を取得するコマンドがあれば便利だろうなと思った。そのコマンドを仮にselectionと名付けたら、Finderで目的のファイルを選択(1回クリック)してから、ターミナルで
$ less $(selection)
としたら良い。調べてみたが、もとからそういうのがあるわけではなさそうなので、作って見ることにした。
JavaScriptでosascript
macのターミナルでmacOSを操作するにはosascriptというコマンドがあって、従来この中でApplescriptを書いて色々やられているようだが、しばらく前からJavaScriptで代替できるようになったそうである。
参考 https://qiita.com/zakuroishikuro/items/1b02378bf9e940602d87
ここは馴染みのあるJavaScriptを使うことにした。
コマンドについては、macのスクリプトエディタのリファレンスで調べる。
ターミナルで実験
$ osascript -i -l JavaScript
とすると、osascript-Javascriptか対話式に実行できる。
今、ホームディレクトリのtestというファイル(1つ)をFinderで選択中とする。
まず
finder = Application('Finder');
finder.selection();
としたら、
=> [Application("Finder").startupDisk.folders.byName("Users").folders.byName("user_name").documentFiles.byName("test")]
とかえってくる。test, test2の2つを選択中だと、
=> [Application("Finder").startupDisk.folders.byName("Users").folders.byName("user_name").documentFiles.byName("test"), Application("Finder").startupDisk.folders.byName("Users").folders.byName("user_name").documentFiles.byName("test2")]
のように、配列に2つ入ってかえってくる。
とりあえず、一つのファイルを操作しよう。
file = finder.selection()[0]
file.name() // => "test"
このように、ファイル名を取得することはできる。が、このファイルオブジェクト(?)から直接フルパスを取得することはできないようだった。取れるのは、一つ上のディレクトリである。
file.container().name() // => "user_name"
どんどん辿っていけば、フルパスを作れそうである。
file.name() // => "test"
file.container().name() // => "user_name"
file.container().container().name() // => "Users"
file.container().container().container().name() // => "Macintosh HD"
file.container().container().container().container().name() // => "ユーザーのMacBook Air"
file.container().container().container().container().container().name()
// => !! Error on line 1: Error: オブジェクトを取得できません。
ここから、Macintosh HD以降は切り捨てて、/Users/user_name/testという文字列を作ろう。
スクリプト
以上の実験をもとに、以下のようなスクリプトを作った。
# !/usr/bin/osascript -l JavaScript
const finder = Application('Finder');
const getFullPath = (file) => {
const path = []; // ここに追加していく
while(true){
name = file.name(); // 名前を取得
if(name === 'Macintosh HD'){ // Macintosh HDまで到達したら
break; // ループを抜ける
}
else{
path.unshift(name); // pathの先頭に追加
file = file.container(); // 上のディレクトリに移動
}
}
return '/' + path.join('/'); // Macintosh HD以下を/で繋げる。先頭にはルートをつける
};
finder.selection().map(getFullPath).join('\n'); // 最後にこれを複数のファイルに対して施して、改行で連結して出力
このファイルをselectionと名付けて、実行権限をつけ、パスを通す。
$ selection
# 出力
# /Users/user_name/test
# /Users/user_name/test2
できた!