Macの既存のテキストファイルの特定の行にテキストを挿入するには、ショートカットのシェルアクションを使って編集済みのコピーを作成し、内容を確認してからFinderで名前を変更します。この手順では、使い捨てのサンプルを使って3行目の前に1行挿入します。

ここでは、小さなローカルのプレーンテキストファイルに行を追加し、前後の行の順序を保ちます。Finderからファイルを1つだけ受け取るショートカットを作成します。挿入するテキストと行番号はスクリプト内に記述するため、使い捨てのコピーで同じ編集を簡単に繰り返せます。

「3行目に挿入」とはどういう意味ですか?

この記事では、挿入とは、番号が付いた既存の行の前に新しいテキストを配置することです。元のファイルが3行の場合、3行目の前に Birch を挿入すると、次のように4行になります。

位置 元のファイル 編集後のファイル
1 Cedar Cedar
2 Maple Maple
3 Willow Birch
4 — Willow

行とは、エディタで画面幅に応じて折り返された表示上の行ではなく、改行で区切られたレコードです。空行も数えます。この例では、LF改行で、最終行の後にも改行がある一般的なUTF-8プレーンテキストを使います。この作業ではこれらの条件を保ってください。リッチテキスト文書や、異なるエンコーディングまたは改行を使うファイルには、別の扱い方が必要です。

編集に使うコマンドはmacOSの sed です。数値アドレスは行を1から数え、i コマンドは指定した行の前に挿入テキストを書き込みます。通常、変換後の内容は標準出力に書き出されます。これらの仕様を利用して、ショートカットは別の出力ファイルを作成できます。Apple配布のsedマニュアル

使い捨てのテキストファイルを作成する

ターミナルを開き、次のセットアップブロック全体を貼り付けます。デスクトップに Line Insert Demo という名前のフォルダを作成し、その中に notes.txt という名前の3行ファイルを作成します。そのフォルダ名がすでに存在する場合、セットアップは停止します。もう一度試す前に、新しいフォルダ名を選んでください。

/bin/sh <<'SH'
set -e
demo_dir="$HOME/Desktop/Line Insert Demo"
/bin/mkdir "$demo_dir"
printf '%s\n' 'Cedar' 'Maple' 'Willow' > "$demo_dir/notes.txt"
printf 'Created: %s\n' "$demo_dir/notes.txt"
SH

フォルダの作成では、既存のディレクトリを許可するオプションを意図的に省いています。新しいフォルダが作成された場合にのみファイル書き込み処理が実行されるため、以前のサンプルが上書きされることはありません。Appleのシェルに関するドキュメントでは、printf と出力リダイレクトを使ってテキストファイルを作成する方法が説明されています。シェルの入力と出力

この作業は、その使い捨てフォルダ内で行ってください。Finderでデスクトップを開き、Line Insert Demo を見つけます。ショートカットを作成した後、ここにある notes.txt ファイルを選択します。

適切な入力タイプでFinderショートカットを作成する

ショートカットアプリで Insert Birch Before Line 3 という名前のショートカットを作成します。Appleのドキュメントでは、ツールバーの「追加」ボタンを使ってショートカットを作成し、名前を付け、サイドバーからアクションを追加する方法が説明されています。Macでカスタムショートカットを作成する

次のように設定します。

  1. ショートカットの 詳細 を開き、クイックアクションとして使用 を有効にして、Finder を選択します。
  2. ショートカットの入力ヘッダで、受け付けるコンテンツを ファイル に変更し、ほかのタイプをオフにします。
  3. シェルスクリプトを実行 アクションを追加します。
  4. シェル を /bin/sh、入力 を ショートカットの入力、入力を渡す を 引数として に設定します。
  5. アクションのサンプルスクリプトを、次のセクションにあるプログラム全体に置き換えます。

Appleのドキュメントでは、Finderショートカットを有効にする方法と、受け付ける入力タイプを制限する方法が説明されています。ファイル タイプにはさまざまな種類の書類が含まれるため、この設定によってファイルをショートカットに渡せるようになりますが、テキスト形式の検証は行われません。より厳密なチェックはスクリプトで追加します。Macで作業中にショートカットを実行する、ショートカットの入力を制限する、入力タイプについて

入力の流れが重要です。Finderからショートカットにファイルが渡され、シェルアクションはそのパスを引数として渡します。スクリプトでは $1 として利用できます。シェルアクションの前にテキストを読み取るアクションを置かないでください。このプログラムは、既存のファイルを読み取り、隣接する出力ファイル名を選ぶために、ファイルのパスを必要とします。

Appleは、ショートカットアプリのエディタでシェルスクリプトを直接実行できることを説明しています。スクリプトが無効になっている場合は、ショートカット > 設定 を選択し、詳細 を開いて スクリプトの実行を許可 を有効にします。macOS版ショートカットを使う、ショートカットの詳細設定

行を挿入し、別の出力ファイルを作成する

次のプログラム全体を シェルスクリプトを実行 に貼り付けます。既存の通常ファイルを1つ受け取り、3行目の前に Birch を挿入し、元のパスに .inserted.txt を付けた名前の隣接ファイルに書き出します。

#!/bin/sh
set -eu

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

[ "$#" -eq 1 ] || fail 'Select exactly one example text file.'
file=$1
line=3

case "$file" in
    /*) ;;
    *) fail 'The input must be an absolute file path.' ;;
esac

[ -f "$file" ] || fail 'The input file does not exist or is not a regular file.'
[ ! -L "$file" ] || fail 'Select the example file itself, not a symbolic link.'
[ -r "$file" ] || fail 'The input file cannot be read.'

count=$(/usr/bin/sed -n '$=' "$file") || fail 'Could not count the input lines.'
[ -n "$count" ] || fail 'The input file is empty.'
[ "$line" -le "$count" ] || fail 'The insertion line is beyond the end of the file.'

output="${file}.inserted.txt"
if [ -e "$output" ] || [ -L "$output" ]; then
    fail 'The output name already exists. Inspect or rename that result first.'
fi

if (
    set -C
    /usr/bin/sed "${line}i\\
Birch
" "$file" > "$output"
); then
    printf 'Created edited copy: %s\n' "$output"
else
    fail 'Could not finish the edited copy. Inspect any partial output before retrying.'
fi

sed の式の中にある物理的な改行は意図されたものです。i の後のバックスラッシュ、続く改行、そして独立した行にある挿入テキストをそのまま保ってください。コマンドの構成はApple配布のマニュアルに沿っており、別の sed 実装からコピーした短縮形の挿入表記には依存しません。sedマニュアル:コマンドと挿入テキスト

周囲のチェックは、この作業手順での判断基準です。番号を指定した行の前に挿入するには、その行が存在している必要があります。そのため、このプログラムは空のファイルと、最終行を超える位置を拒否します。また、出力ファイル名がすでに存在する場合も拒否し、シェルのnoclobberモードを有効にして出力ファイルを開く際にも追加で確認します。

スクリプトは元のファイルを読み取り、別のファイルに書き込みます。書き込みに失敗しても元のファイルは残りますが、不完全な出力ファイルが残ることがあります。エラーが発生した場合は処理未完了として扱い、その出力ファイルを削除したり再試行したりする前に内容を確認してください。一度に実行するのは1つだけにし、処理中は元ファイルを変更しないでください。

アクションの出力は、パスを含むテキストのステータスメッセージであり、ショートカットのファイルオブジェクトではありません。編集済みファイルは、スクリプトのリダイレクトによって作成されます。後から ファイルを保存 を追加すると、意図した行挿入ではなく、アクションの出力が保存されます。Appleのドキュメントでは、ファイルを保存 はファイル管理用の共有アクションとして説明されており、行番号を指定した編集機能としては説明されていません。Macのショートカットにおける共有アクションについて

実行して結果を確認し、元のファイル名を維持する

Finderで使い捨ての notes.txt ファイルをControlキーを押しながらクリックし、クイックアクション、Insert Birch Before Line 3 の順に選択します。Appleのドキュメントでは、この起動方法が説明されています。ショートカットが表示されない場合は、詳細設定でFinderが有効になっていることと、受け付ける入力に ファイル が含まれていることを確認してください。Macで作業中にショートカットを実行する

正常に実行されると、デモ用フォルダには notes.txt と notes.txt.inserted.txt の両方が入っています。後者を開き、内容が次のとおりであることを確認します。

Cedar
Maple
Birch
Willow

ターミナルから次のコマンド全体を使って出力を確認することもできます。

/bin/cat "$HOME/Desktop/Line Insert Demo/notes.txt.inserted.txt"

編集後の内容を元のパスに置くには、サンプルの書類を閉じてから、Finderで次の2回の名前変更を行います。最初に notes.original.txt が使われていないことを確認してください。すでに存在する場合は、別の未使用のバックアップ名を選びます。

  1. notes.txt を選択して Return キーを押し、名前を notes.original.txt に変更して、もう一度 Return キーを押します。
  2. notes.txt.inserted.txt を選択して Return キーを押し、名前を notes.txt に変更して、もう一度 Return キーを押します。
  3. 新しい名前になった notes.txt を開き、4行あることを確認します。

Appleのドキュメントでは、項目を選択して Return キーを押すと名前を変更できると説明されています。両方の名前で最後の .txt 拡張子を維持してください。Finderで名前の重複が報告された場合は、停止して既存の項目を確認してから、使われていない名前を選びます。Macでファイル、フォルダ、ディスクの名前を変更する

この手順を終えると、編集後の内容は notes.txt に、元の内容は notes.original.txt に置かれます。元のパスにあるファイルがどれかは入れ替わりますが、元ファイルの実体が維持されるわけではなく、Finderのタグ、拡張属性、その他のメタデータが引き継がれる保証もありません。

意味を変えずに挿入位置を調整する

別の使い捨てファイルで試す場合は、line=3 を既存の行番号に変更し、Birch を単純な1行のテキストに置き換えます。表示されている挿入構文はそのままにしてください。この例のテキストには引用符、ドル記号、バッククォート、バックスラッシュは意図的に含まれていません。任意のテキストを使う場合は、追加のシェルおよび sed のクォート処理が必要です。

スクリプトを編集する前に、次の判断表を確認してください。

変更内容 操作
1行目の前にテキストを置く 空でないサンプルファイルで line=1 を設定します。
別の既存行の前にテキストを置く line に、その正の行番号を設定します。
最終行の後にテキストを追加する 別の追記処理を使います。このプログラムは存在しない対象行を拒否します。
空のファイルに挿入する 最初の内容を別途作成します。指定できる既存行がありません。
同じショートカットを2回実行する 先に作成した出力を確認します。元ファイルを置き換えた後にもう一度実行すると、同じテキストがさらに1つ挿入されます。

このデスクトップでの作業では、選択したファイル、挿入位置、完成した結果、最終的なファイル名を確認することがポイントです。4行の例が正しくできたら、同じ手順を使って、元のテキストを残したまま別の単純な挿入を試せます。

出典