Macショートカットからシェルスクリプトにテキストを渡し、1つのローカルフォルダ内で最も新しく変更されたテキストファイルを選んで入力内容を追記します。この手順では使い捨てのサンプルファイルを使い、フォルダが空の場合や最新のタイムスタンプが同じ場合は処理を停止します。

ここで扱うのは、毎回手動でファイルを選ばずに、既存のプレーンテキストファイルに短い項目を追加するという具体的な作業です。Appleは、Macショートカット内でのシェルスクリプトのサポートについて説明しています。以下のワークフローでは、そのサポート機能と、zshで文書化されているファイルの選択方法および追記動作を組み合わせます。macOS用ショートカットを使う

「最新ファイル」の定義を決める

この記事では、最新を最も最近に変更されたという意味で定義します。スクリプトが対象にするのは、指定したフォルダ直下にある、名前の末尾が小文字の .txt で、表示されている通常ファイルのみです。サブフォルダとシンボリックリンクは対象外です。これらの選択ルールは、zshのファイル名パターンと修飾子に基づいています。展開

この定義は繰り返し実行する際に影響します。ファイルに追記すると変更時刻が更新されるため、通常はそのファイルが引き続き最新の対象ファイルになります。新しく作成された最新の文書を対象にしたい場合、変更時刻とは別のルールになります。このワークフローが作成日時による選択を実装していると思い込まないでください。

ショートカットを作成する前に、作業に合ったルールを選んでください。

想定する作業 この例に合うか
最も最近に編集された .txt ファイルに追記する はい
ファイル名に含まれる日付が最も新しいファイルに追記する いいえ。ファイル名の日付は解釈されません
最も最近に作成されたファイルに追記する いいえ。作成時刻は使用しません
サブフォルダ内のファイルも含める いいえ。選択対象は1つのフォルダ内に限られます
リッチテキスト文書やPDFに追記する いいえ。この例ではプレーンテキストを書き込みます

Finderを使うと、目視で確認できます。フォルダをリスト表示で開き、「変更日」列の見出しをクリックしてください。必要であればもう一度クリックして、最新の項目が先頭になるようにします。Appleは列による並べ替えと順序の反転について説明しています。Finderの表示は結果の確認に役立ちますが、スクリプトは独自に対象を選択します。MacのFinderで項目を並べ替える/整理する

使い捨てのサンプルフォルダを作成する

この例では、ホームフォルダ内に Shortcut Append Demo というフォルダを使用します。既存の内容を再利用せず、その名前がすでに存在する場合はセットアップを停止するようにしています。合成テキストファイルを2つ作成し、2つ目のファイルの変更時刻が後になるよう、2秒間隔を設けます。

ターミナルを開き、次のセットアップブロック全体を貼り付けてReturnキーを押します。引用符で囲んだヒアドキュメントは別のzshプロセスでコマンドを実行するため、セットアップに失敗するとそのプロセスは終了します。

/bin/zsh <<'ZSH'
emulate -L zsh
setopt ERR_EXIT
folder="$HOME/Shortcut Append Demo"

if ! /bin/mkdir "$folder"; then
  printf '%s\n' 'Setup stopped: use a new folder name if this one exists.' >&2
  exit 1
fi

printf '%s\n' 'Sample entry: blue notebook.' > "$folder/older.txt"
/bin/sleep 2
printf '%s\n' 'Sample entry: green notebook.' > "$folder/newer.txt"
printf 'Example folder: %s\n' "$folder"
ZSH

セットアップでは、新しいフォルダが正常に作成された後にのみ、出力リダイレクトを使ってファイルを作成します。Appleは、コマンドの出力をファイルに書き込む通常の出力リダイレクトと、ファイル末尾に出力を追加する追記リダイレクトを区別しています。Macのターミナルで入力と出力をリダイレクトする

フォルダがすでに存在するというメッセージが表示されたら、別の使い捨ての名前を選び、以下のセットアップとショートカットスクリプトの両方でフォルダの割り当てを変更してください。既存のフォルダに対して、ファイルを書き込む行だけを再実行しないでください。

ショートカットを作成し、テキスト入力を保持する

ショートカットアプリで新しいショートカットを作成し、名前を Append to Newest Text File にします。アクション検索を使って、以下のアクションを追加します。Appleは、アクションライブラリの検索方法と、Show Info で各アクションが受け取る入力および出力を確認する方法を説明しています。Macのショートカットでアクションリストを操作する

  1. Text アクションを追加し、合成テキスト Sample entry: orange notebook. を入力します。
  2. その直後に Run Shell Script を追加します。
  3. シェルを /bin/zsh に設定します。
  4. スクリプトの入力を、直前の Text アクションの出力に設定します。
  5. Pass Input を as arguments に設定します。
  6. スクリプト欄の内容を、次のセクションにあるスクリプト全体に置き換えます。

意図する接続は、1つのText値を1つのスクリプト引数に渡すことです。スクリプトはその引数を $1 として読み取ります。成功時の出力は、保存先のパスを含むテキスト確認メッセージです。このパスはショートカットのFileオブジェクトではなく、出力もファイル全体の内容ではありません。

入力は Text の出力に接続したままにしてください。ファイル、ファイル名のリスト、またはショートカットの無関係な入力を渡すと、スクリプトに届く内容が変わります。スクリプトは引数の数を確認するため、想定外の入力の集まりが複数の追記項目になることはありません。

スクリプトが無効になっている場合は、Shortcuts > Settings を開き、Advanced を選択して、Allow Running Scripts を有効にしてください。これらは、ショートカットでスクリプトを実行できるようにするAppleの文書化された設定です。Appleのスクリプト設定手順

ファイルを選択して追記するスクリプトを追加する

プログラム全体を Run Shell Script に貼り付けます。ダウンロードしたツールや別のスクリプトファイルは必要ありません。フォルダの割り当ては、上記の使い捨てセットアップと一致します。

emulate -L zsh
unsetopt CLOBBER APPEND_CREATE

fail() {
  printf '%s\n' "$1" >&2
  exit 1
}

(( $# == 1 )) || fail 'Expected exactly one text input.'
[[ -n "$1" ]] || fail 'The text input is empty.'

folder="$HOME/Shortcut Append Demo"
[[ -d "$folder" ]] || fail 'The example folder does not exist.'

files=( "$folder"/*.txt(N.om) )
(( ${#files} > 0 )) || fail 'No eligible .txt files were found.'

newest="${files[1]}"

if (( ${#files} > 1 )); then
  [[ "$newest" -nt "${files[2]}" ]] ||
    fail 'The newest timestamp is tied or the folder changed. Check the files.'
fi

[[ -f "$newest" && ! -L "$newest" ]] ||
  fail 'The selected file is no longer an eligible regular file.'
[[ -w "$newest" ]] || fail 'The selected file is not writable.'

if ! printf '\n%s\n' "$1" >> "$newest"; then
  fail 'Append failed; inspect the selected file before retrying.'
fi

printf 'Appended to: %s\n' "$newest"

選択式は、一致するファイルパスの配列を作成します。(N.om) では、N が一致なしを許容し、. が通常ファイルに対象を限定し、om が変更時刻で並べ替えて最も新しいものを先頭にします。パスを配列に保持することで、空白を含むファイル名が分割されるのを防げます。展開

次の確認では、先頭のファイルが2番目のファイルより厳密に新しいことを要求します。変更時刻が同じ場合、ショートカットは一方を黙って選ばずに停止します。zshでは、ファイルの新しさを比較する -nt と、ここで使う通常ファイル、シンボリックリンク、書き込み可能ファイルの判定について説明しています。条件式

追記コマンドは固定の printf 書式を使い、入力内容を %s 引数として渡します。そのため、入力内のパーセント記号やバックスラッシュは追加の書式指定ではなくテキストとして扱われます。先頭の改行で既存のテキストと項目を分け、末尾の改行で項目を終端します。ファイルがすでに改行で終わっている場合、項目間に空行ができます。シェル組み込みコマンド

スクリプトは CLOBBER と APPEND_CREATE も解除します。両方のオプションを解除すると、保存先が存在しない場合に追記リダイレクトが失敗するとzshの文書に記載されています。選択したファイルが追記前に消えた場合、古いパスに代わりのファイルを作成せず、スクリプトがエラーを報告するために重要です。リダイレクト

サンプルファイルで結果を確認する

ショートカットを1回実行します。サンプルフォルダに手を加えていなければ、保存先は newer.txt になるはずです。そのファイルを開き、次の内容になっていることを確認します。これは例から導かれる想定結果であり、MacのUIテストを完了したという主張ではありません。

Sample entry: green notebook.

Sample entry: orange notebook.

older.txt も開きます。こちらには Sample entry: blue notebook. だけが残っているはずです。両方のファイルを確認すると、保存先の選択と、もう一方のファイルが保持されていることの2点を検証できます。

Text アクションを Sample entry: yellow notebook. に変更して再実行し、2つ目の合成項目を試します。他の対象ファイルがそれより新しくなっていなければ、newer.txt に区切られた項目がもう1つ追加されるはずです。同じ入力でショートカットを2回実行すると、その入力は2回追記されます。このプログラムは重複項目を検出しません。

これらの例は文書と照合しましたが、ここでは実行していません。利用可能な環境にはmacOSのショートカットもzshもありません。フォルダの割り当てを変更する前に、お使いのMacで使い捨てファイルを使った確認を完了してください。

空のフォルダ、名前の衝突、ファイルの変更について

このワークフローには既存の保存先が必要です。フォルダがない場合、空の場合、または対象外の項目しかない場合、追記前にエラーになります。既定のファイルを作成したり、サブフォルダを選んだり、別名の文書に切り替えたりはしません。

名前の衝突は、保存先を作成しないことで回避しています。セットアップでは、フォルダ名がすでに存在する場合に停止します。通常のショートカット実行では、選択したファイルの名前はそのままです。スクリプトは名前を変更せず、2つ目のコピーも保存しません。ファイルが見つからない場合の動作は、文書化されているzshの追記オプションで制御されます。リダイレクト

想定と結果が異なる場合は、次の簡単な手順で診断してください。

  1. フォルダの割り当てを確認します。 セットアップで作成したフォルダと一致している必要があります。
  2. 対象条件を確認します。 サンプルのパターンは、フォルダ直下にある、表示された通常ファイルのうち、名前が小文字の .txt で終わるものを対象にします。
  3. 変更時刻の順序を確認します。 Finderで「変更日」を確認してください。ファイルを編集すると、次回の保存先になる可能性がある点に注意します。
  4. タイムスタンプが同じか確認します。 対象にしたいサンプルファイルを後から編集して保存し、もう一度順序を確認します。
  5. アクションの接続を確認します。 1つのテキスト値が1つの引数としてシェルに渡される必要があります。

このスクリプトは、実行中にフォルダの内容が変わらないことを前提としています。選択と書き込みは別の操作です。その間に別のプロセスがファイルを編集、置換、または追加する可能性があります。これらの確認によってワークフローがトランザクションになるわけではなく、書き込みに失敗すると項目の一部だけが追記される可能性があります。追記エラーの後に再試行する前に、ファイルを確認してください。

標準のファイルフィルタを使う場合

Appleの説明によると、Filter Files はコンテンツを受け取り、フィルタで絞り込み、一致した結果を次のアクションに渡すアクションです。一般的なフィルタコントロールでは、結果の並べ替えや件数制限ができます。これらの操作はファイルの選択には役立ちますが、それ自体でテキストを追記するものではありません。検索とフィルタのアクションの概要、フィルタパラメータを追加する

この手順では、ファイルのパターン、同じ時刻の場合の動作、既存ファイルの要件を明確にするため、シェルスクリプト内で選択と書き込みを行います。ファイルアクションを使って別のアクション列を作る場合は、まず各アクションの Show Info を確認してください。Fileの結果、Textに変換されたファイル内容、Textとして表されたパスは、それぞれ異なる値です。Appleは入力と出力の型を特定できるように、これらのアクション説明を用意しています。Macのショートカットでアクションリストを操作する

サンプルが想定どおり動作したら、変更時も同じ明確な前提を保ってください。テキスト項目1つ、指定したローカルフォルダ1つ、そして対象条件に合うファイルのうち最も新しいもの1つです。こうすれば実行のたびに予測しやすくなり、ショートカットが停止したときも調査箇所を絞り込めます。

参照元