Help us understand the problem. What is going on with this article?

macOSのFinderで選択中のパスをターミナル上で取得する

More than 1 year has passed since last update.

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

できた!

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした