1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

[Mac] ターミナルから指定したファイルをファインダーに表示するコマンド

Posted at

その前に、

ターミナルから特定のフォルダのファインダーを開く

こちらの記事にあるように、

$ open フォルダパス

ですね。これは有名なので、みなさんご存知かと思います。

次に、

ターミナルから指定したファイルをファインダーに表示

-Rオプションを指定します。

$ open -R ファイルパス

ところが、
複数のファイルを指定した場合は、それらすべてのファイルが選択された状態で表示して欲しいのですが、最後の1ファイルしか選択されていません。

しかも、複数のファイルを指定した場合、極端に動作が遅くなります。

そこで、同機能のコマンドを自作することにします。

コマンド自作

複数のファイルを指定した場合は、すべてのファイルが選択された状態で表示するコマンドを作成します。

使用するAPI

使用するAPIは、activateFileViewerSelecting(_:)

activateFileViewerSelecting(_:)
Activates the Finder, and opens one or more windows selecting the specified files.

これ、実現したいことが、まんま叶うAPIです。
ファインダーに表示したいファイルのURLを配列にして引数に渡すだけ。複数のファイルを指定できます。必要により、複数のFinderウインドウが開きます。

Swiftコード

自分はコマンド名をShowInFinderとしましたが、もっと短く全部小文字の方が使い易いと思います。

コードは以下の通り。

ShowInFinder.swift
import System
import AppKit

let main: () = {

    var urls = [URL]()
    let currentDirectory = FilePath(FileManager.default.currentDirectoryPath)
    for argv in CommandLine.arguments.dropFirst() {
        let path = if argv.first! != "/" {
            currentDirectory.appending(argv).string
        } else {
            argv
        }
        let url = URL(fileURLWithPath: path)
        //print(url.path)
        if FileManager.default.fileExists(atPath: url.path) {
            urls.append(url)
        } else {
            let msg = "file \(argv) not found."
            print(msg, to: &stderr)
        }
    }

    guard urls.count > 0 else {
        let commandPath = FilePath(stringLiteral: CommandLine.arguments.first!)
        let commandName = commandPath.components.last!
        let usage = """
            \(commandName): arguments missing.
            Usage: \(commandName) file1 [ file2 [ file3 ... ] ]
            """
        print(usage, to: &stderr)
        return
    }

    NSWorkspace.shared.activateFileViewerSelecting(urls)

}()

extension UnsafeMutablePointer: TextOutputStream where Pointee == FILE {
    public mutating func write(_ string: String) {
        guard let data = string.data(using: .utf8) else { return }
        _ = data.withUnsafeBytes { bytes in
#if os(Linux)
            Glibc.write(fileno(self), bytes.baseAddress!, data.count)
#else
            Darwin.write(fileno(self), bytes.baseAddress!, data.count)
#endif
        }
    }
}

activateFileViewerSelecting(_:) に渡すURLは、絶対パス(完全パス)である必要があるため、"/"で始まっていないパスには、カレントディレクトリパスに連結しています。

存在しないパスは無視します。

最後のextensionは、printstderrに出力するための汎用的なもので、本コマンドに直接は関係しません。

ビルド

次のコマンドでビルド(コンパイル&リンカ)します。

コンパイル&リンカ
$ swiftc ShowInFinder.swift -o ShowInFinder

使い方

ビルドして出来たコマンドにpathを通します。もしくはpathの通っているフォルダにコピーします。

$ ShowInFinder
ShowInFinder: arguments missing.
Usage: ShowInFinder file1 [ file2 [ file3 ... ] ]

$ ShowInFinder hoge.png fuga.png

$ ShowInFinder *.png

環境

執筆時の環境は以下の通り

$ uname -a
Darwin Mac-mini.local 23.4.0 Darwin Kernel Version 23.4.0: Wed Feb 21 21:44:06 PST 2024; root:xnu-10063.101.15~2/RELEASE_ARM64_T8103 arm64

$ swiftc --version
swift-driver version: 1.90.11.1 Apple Swift version 5.10 (swiftlang-5.10.0.13 clang-1500.3.9.4)
Target: arm64-apple-macosx14.0

以上です

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?