目次
Google Apps Script(GAS)でスプレッドシートを自動化する際、既存のフォーマットを維持したまま新しいシートを起こす処理は非常によく使われます。月次集計のひな形を月初に複製したり、日次の作業ログシートを定時に自動生成したりといった用途です。しかし、シート操作のスクリプトを書くときに「単に複製するだけ」のつもりで組み込むと、引数の渡し方や命名規則の競合によって意図しない挙動やスクリプト停止に直面します。
この記事では、GASで現在のシートを複製して新しい名前をつける手順と、実務で発生しやすいシート重複の落とし穴を回避する組み立てについて掘り下げます。
copyToという名前が招く引数の渡し方と別ブックへの誤爆
Google Apps Scriptでシートを複製する際に主軸となるメソッドは、Sheetクラスに用意されているcopyTo()です。ここで最初に引っかかりやすいのが、「このメソッドは何を引数に取るのか」という点です。JavaScriptの一般的なオブジェクト操作や他言語のAPIに慣れていると、引数に新しいシート名として文字列を渡したくなったり、あるいは無引数で実行すれば現在のスプレッドシートの末尾にそのまま複製が作られると思い込んでしまいがちです。
実際には、copyTo()が必須の引数として要求するのは「コピー先となるSpreadsheetオブジェクト」です。たとえ現在開いている同じスプレッドシート内にシートを増やしたいだけであっても、引数を空にして呼び出すことはできず、親となるスプレッドシート自身を渡さなければなりません。文字列で新しい名前を直接渡そうとすると型エラーになります。
この仕様の背景には、copyTo()が「別のスプレッドシートファイルへシートを転送する」機能も兼ねているという設計があります。そのため、同一ブック内での複製は、いわば「自分自身をコピー先スプレッドシートとして指定した特殊な転送」として処理されます。引数に渡す対象を取り違え、誤って別の開いているSpreadsheetオブジェクトを渡してしまうと、全く意図していない別ファイルの中に不要なシートが生成され、複製元では何も起きていないように見えるというトラブルが起きます。同一ファイル内での複製を目的とする場合は、必ずアクティブなスプレッドシート自身を取得して引数に流し込む必要があります。
また、複製処理が行われた瞬間、内部ではデータ値だけでなく、セル結合、フォントサイズ、背景色、枠線、条件付き書式、セルに入力された数式にいたるまで、シート上の視覚的・論理的な構造がすべて引き継がれます。これは便利な反面、数式内の相対参照がどのように解決されるかや、大容量シートを複製した際のGASの実行時間への影響を意識しておく必要があります。
現在のシートを複製して新しい名前をつける記述
同一スプレッドシート内でアクティブなシートを複製し、任意の名前を設定する処理は、以下の手順で記述します。アクティブなスプレッドシートの取得、対象シートの取得、同一スプレッドシートを宛先とした複製の実行、そして生成された新規シートオブジェクトに対するリネームという流れです。
function duplicateActiveSheet() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getActiveSheet();
const newSheet = sheet.copyTo(ss);
newSheet.setName("複製シート");
}
このコードの挙動を順を追って確認します。まずSpreadsheetApp.getActiveSpreadsheet()によって現在開かれているスプレッドシート全体を取得し、変数ssに格納します。次にss.getActiveSheet()で、ユーザーが現在表示している、あるいはスクリプト実行時点でアクティブになっているシートを取得します。ここまでは準備段階です。
核心となるのがsheet.copyTo(ss)の行です。対象シートに対してcopyTo()を呼び出し、引数に親であるssを渡しています。このメソッドが実行された瞬間に、スプレッドシート内に新しいシートが物理的に生成されます。そして重要なのは、copyTo()メソッドが戻り値として「新しく作成されたSheetオブジェクト」を返すという点です。上記のコードでは、この返り値を変数newSheetとして受け取っています。
最後に、生成されたnewSheetに対してsetName("複製シート")を実行し、名称を決定しています。この一行を挟むことで、複製直後に割り当てられた仮の名前から、業務で必要な名称へと即座に切り替えることができます。GAS シート 複製を自動化する上での最小構成でありながら、後続の処理でこの新規シートに値を書き込んだり、特定のセルをクリアしたりする足がかりになる記述です。
自動付与されるシート名とsetNameを省略した際のリスク
前述の処理において、もしnewSheet.setName()を実行しなかった場合、新規シートにはどのような名前が付くのでしょうか。Googleスプレッドシートの仕様として、copyTo()で作成されたシートには、自動的に「(元のシート名) のコピー」という名称が割り当てられます。例えば「原本」というシートを複製した場合は「原本 のコピー」となります。さらにその状態で再度複製を行うと「原本 のコピー のコピー」というように、末尾に文字列が積み重なっていきます。
手動でシートを右クリックして複製したときと同じ挙動ですが、プログラムから後続のシートを参照する運用をしている場合、この挙動は大きなリスク要因になります。スクリプトが特定の命名規則を前提として他の処理(別シートからのデータ集計やVLOOKUPなどの参照数式)を組んでいた場合、「〜のコピー」という不規則なスペース混じりの名前が紛れ込むことで、シート検索に失敗したり数式がエラーを起こしたりします。
また、複製直後のシートはスプレッドシートのタブ並びの一番右端や、元シートの直後など、スプレッドシート側の内部判断で挿入されます。名前を意図通りに付け替えないまま放置すると、どのシートがどのタイミングで生成されたものなのかが目視でもスクリプト上でも判別がつかなくなります。テンプレートシートを元に月次レポートシートを自動生成する場合などに有効な手法であるからこそ、複製の直後には必ず明示的な名前へリネームするステップをセットで記述することが求められます。
同名シートによるエラーの回避と実務で破綻しない命名設計
シートの複製処理において、もっとも頻繁にスクリプトを異常終了させる落とし穴が「同名シートの存在」です。Googleスプレッドシートでは、1つのファイル内にまったく同じ名前のシートを2つ以上存在させることができません。すでに「2025-05」というシートが存在する状態で、新しく複製したシートに対してnewSheet.setName("2025-05")を実行すると、スクリプトは例外をスローしてその場で強制停止します。
複製先の名前がすでに存在するとエラーになります。この事態を防ぐためには、複製処理を走らせる前に「その名前のシートがすでに存在していないか」を確認する防護策を組み込むか、あるいは絶対に名前が重複しないような命名ルールを採用する必要があります。
まず考えられるのは、日付や時間を動的にシート名へ組み込むアプローチです。例えば日次バッチで動かす場合は実行日の年月日(20250501など)を付与し、1日に複数回動く可能性がある処理であればタイムスタンプまで含めることで、名前の衝突を物理的に起こりにくくします。既存のシート名と重複しないよう、日付を付与する等の命名規則が推奨されるのはこのためです。
さらに安全性を高めるには、名前を変更する前にss.getSheetByName(targetName)を実行して重複判定を行います。もしこのメソッドの戻り値がnullでなければ、同名のシートがすでに存在していることを意味します。実務では、同名シートが存在した際に「処理を中断してログを残す」「既存シートを削除して作り直す」「末尾に連番を振る」といった運用ルールに応じた分岐をあらかじめ記述しておく必要があります。以下に、安全に名前の重複を検知してリネームを行う実装例を示します。
function duplicateSheetSafely() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const templateSheet = ss.getSheetByName("テンプレート");
if (!templateSheet) {
console.error("複製元のテンプレートシートが見つかりません");
return;
}
// 例として今日の日付を付与したシート名を生成する
const today = Utilities.formatDate(new Date(), "Asia/Tokyo", "yyyyMMdd");
const targetSheetName = "レポート_" + today;
// 既に同名のシートが存在するか確認
const existingSheet = ss.getSheetByName(targetSheetName);
if (existingSheet) {
console.warn("同名のシートが既に存在するため、処理をスキップまたは別名にします: " + targetSheetName);
return;
}
// 重複がないことを確認してから複製と命名を実施
const newSheet = templateSheet.copyTo(ss);
newSheet.setName(targetSheetName);
// 必要に応じてシートの位置を調整(先頭に移動する場合)
ss.setActiveSheet(newSheet);
ss.moveActiveSheet(1);
}
上記のコードでは、まず複製元となるシートが実在するかを検証し、次に作成したいシート名(ここでは日付入り)がすでに使われていないかをgetSheetByName()で確認しています。存在していた場合は安全にリターンしてスクリプトの異常終了を防ぎます。問題がない場合のみcopyTo()を実行し、その直後にsetName()で目標の名前を割り当てています。
また、複製直後のシートは末尾に追加されることが多いため、実務で「常に最新シートを一番左に置きたい」という要件がある場合は、上記コードの末尾のようにsetActiveSheet()とmoveActiveSheet(1)を組み合わせてタブ位置まで整えておくと、ユーザーがスプレッドシートを開いたときの視認性も担保できます。複製、リネーム、重複制御、位置調整を一連の流れとして捉えておくことが、安定したシート運用の鍵となります。

