文系プログラマによるTIPSブログ

文系プログラマ脳の私が開発現場で学んだ事やプログラミングのTIPSをまとめています。

macのAutomatorでhomebrewのコマンドをFinderのサービスから実行できるようにする

homebrewでインストールしたコマンドをFinder上で画面ポチポチで実行可能にしてみましょう〜

f:id:treeapps:20180418114029p:plain

モチベーション

私「このファイルRARか。解凍できん・・・」
敵「App StoreでThe Unarchiverインストールすれば?」
私「RARアーカイバなんてインストールしたくない。アンインストール時にゴミが残るの嫌だし挙動をコントロールしたい。っていうか今時どんな理由があってRAR形式なんて使うんだよ・・・」
敵「うざ」
私「homebrewでインストールしたp7zipならRAR解凍できる。」
敵「何それキモ」
私「Automatorなら確かシェルスクリプト呼べるから、画面からポチポチできそう」


こんな動機です。他にも、App Storeには無いけど、homebrewには有るコマンドをFinder上でトラックパッドでポチポチ実行したいしたい場合もです。

何故ターミナルからコマンドを実行しないかというと、「いちいちターミナルでコマンド実行するの大変じゃない?ファイル名に日本語やスペースが混じってると面倒だし」という物凄くつまらない理由になります。

このつまらない願望をAutomatorなら実現できるので、やってみましょう。

RARの解凍をサービス化してFinderからポチポチできるようにする

homebrewでp7zipをインストールする

brew install p7zip

Automatorからサービスを作成する

アプリケーションからAutomatorを起動します。
f:id:treeapps:20190430031709p:plain

Automatorを起動するといきなり以下のようなダイアログが表示されます。色々表示されていますが、ここは新規作成ボタンをクリックします。

f:id:treeapps:20190430055525p:plain

新規作成ボタンをクリックすると以下のようなダイアログが表示されます。書類の種類はクイックアクションを選択し、選択ボタンをクリックします。少し解りにくいですが、サービスに登録するにはクイックアクションを選択します。

f:id:treeapps:20190430033408p:plain

選択ボタンをクリックすると以下のような画面が表示されます。いきなり大量の機能が表れて面くらいますが、虫眼鏡アイコンのテキストボックスにシェルスクリプトと入力すると、以下のように大量のメニューの中からシェルスクリプトを実行が絞り込まれます。

f:id:treeapps:20190430033809p:plain

シェルスクリプトを実行をドラッグし、ワークフローを作成するには、ここにアクションまたはファイルをドラッグしてください。というエリアにドロップします。

f:id:treeapps:20190430034118p:plain

ワークフローが受け取る現在の項目をファイルまたはフォルダに、シェルを/bin/bashに変更し、テキストエリアに以下をコピー&ペーストします。

while read file; do
  # ファイルではない場合はスキップ
  if [ ! -f "$file" ]; then
    continue
  fi
  # パスが通っていないのでフルパスで解凍する
  /usr/local/bin/unrar x "$file" "$(dirname "$file")"
done
# 完了を知らせる音を鳴らす
afplay /System/Library/Sounds/Glass.aiff

※ Automatorはログインシェルを実行してくれないのでunrarをフルパスで記述しています

f:id:treeapps:20190430042744p:plain

テキストエリアに上記スクリプトを入力後、cmd + sで保存します。ここで保存した名前がそのままサービス名になります。今回は「RARを解凍」という名前にしてみました。

f:id:treeapps:20190430034925p:plain

尚、保存したファイルの実態は/Users/ユーザ名/Library/Services/RARを解凍.workflowに保存されています。

これで完成です!

では早速試してみましょう。

単数・複数のrarファイルをサービスで解凍するGIFアニメ

f:id:treeapps:20190430043827g:plain

おまけ:フォルダ毎にzip圧縮

例えば以下のように沢山のディレクトリが有るとします。

.
├── sample1
├── sample2
・・・略・・・
├── sample49
└── sample50

このフォルダを1ファイルのzipに圧縮するのではなく、フォルダ毎にzip圧縮をしたい、更にフォルダは削除してzipファイルのみ残したい場合、以下のスクリプトをAutomatorでサービス化するだけです。サービス化手順は前述と全く同じです。

while read f;do
  if [ ! -d "$f" ]; then
    continue
  fi
  cd "${f%/*}"
  zip -0mr -b /tmp "${f##*/}".zip "${f##*/}" -x "*/.DS_Store" "*/Thumbs.db"
done
afplay /System/Library/Sounds/Glass.aiff

こちらは、以下の記事を参考にカスタマイズした形になります。
mattintosh.hatenablog.com

GIFアニメで挙動を確認する

f:id:treeapps:20190430053019g:plain

おまけ:画像サイズの50%化

なんでこんな機能が必要になるかというと、retinaディスプレイで画面キャプチャを取得すると、解像度の問題か、巨大な画像(2倍のサイズ)になってしまうためです。それを等倍に戻すためにこれが便利だったりします。

この機能に関しては標準機能のみで行った方が楽なので、通常のワークフローのみで作成します

ワークフローが受け取る現在の項目をイメージファイルに、ワークフローの1件目をFinder項目を複製に、ワークフローの2件目をイメージをサイズ調整にし、比率(パーセント)指定を選択して値に50を指定し、保存すれば完了です。

f:id:treeapps:20190430052137p:plain

元のファイルを削除せずコピーしてからリサイズするので、操作を誤っても元ファイルへの影響は無いので安心です。

GIFアニメで挙動を確認する

f:id:treeapps:20190430053258g:plain

トラブルシューティング

作成したサービスがメニューに出てこないんだけど?

ワークフローが受け取る現在の項目の設定値が誤っていると、メニューに表示されない事があります。

例えば「ワークフローが受け取る現在の項目」を「自動(テキスト)」が選択されている場合、フォルダを右クリックしてもサービスに表れません。選択値の通り、テキストファイル上で右クリックした場合のみ選択できるようになります。従って、対象が画像なのか、フォルダなのか、等を考慮して適切に設定する必要があります。

homebrewのコマンドが実行されてないっぽいんだけど?

Automatorはログインシェルを実行してくれないため、.bashrcや.zshrcを参照しないため、環境変数やパスが未設定の状態で実行されます。

これに対応するにはフルパスで記述する等が必要になります。

コマンド実行後通知できない?

# コマンドのインストール
brew install terminal-notifier
# 通知テスト
/usr/local/bin/terminal-notifier -title "title" -subtitle "subtitle" -message "テスト"

これをスクリプトの最後等に挟むと通知もできます。

while read file; do って何だよ

「while read file; do」は標準入力(stdin)から選択された複数のファイル名を受け取っています。

何故標準入力(stdin)なのかというと、Automatorのワークフローでそう設定したためです。

f:id:treeapps:20190430062220p:plain

もし「入力の引き渡し方法」を「引数として」を選択した場合、スクリプトの1行目を以下のように修正する事で動くようになります。

while read file; dofor file in "$@"; do

これは単にシェルスクリプトの処理の問題なだけなので、使い慣れている方で記述すればいいかなと思います。

使わないサービスを非表示にしたいんだけど?

システム環境設定 -> キーボード -> ショートカットタブを選択 -> リストボックスからサービスを選択 -> 表示したいもののみチェックする

f:id:treeapps:20190430061517p:plain

尚、サービスの数が5個以上の場合はサービスというサブメニューが表示され、5個より少ない場合は以下のようにサブメニューの代わりにコマンド名が直接表示されるようです

f:id:treeapps:20190430055140p:plain

自作したサービスを削除したいんだけど?

自作サービスは /Users/ユーザ名/Library/Services/に保存されているので、ここにあるファイルを削除するだけで、リアルタイムに削除が反映されるようです。

恐らく右クリックしてサービスメニューを展開したタイミングで都度このファイル群を参照しているため、リアルタイムに反映されるのだと思われます。

雑感

Windowsでは使えないので汎用性には大変疑問が残りますが、個人用途ではAutomatorは非常に有用だったりします。

特にシェルスクリプトが実行可能という事は、プログラマの皆様なら何ができるか想像できますね?

スクリプトを書かなくてもUIだけで構築できるので、実は色々楽だったりします。例えば画像サイズ50%化ですが、macにはsipsという画像操作コマンドがありますが、これは比率を指定できないため、ImageMagick等を別途インストールする必要があります。しかしそれをするためだけに巨大で脆弱性満載なものをインストールしたくありません。そんな時標準ワークフローが利用すると簡単に実現できるので楽です。

今回のように、App Storeからインストールしたくない系コマンドは沢山あると思うので、サービス化等をしてオペレーションを簡単にしておきたいですね。