スクリプトを書くときには中間ファイルを作業ディレクトリに作ってはいけない

March 5, 2020 by Yuta Urushiyama

プログラムの知識が多少は身についてくると,必要なときにチョチョイとスクリプトを書くことができるようになる. そのため,個人所有のPC上でも繰り返しの作業を自動化するためにスクリプトを書く場合が生じる. しかし,元来にしてスクリプトの世界はその入口の広さに見合わないほど奥深いものである. そしてそこには,個人所有のPC特有の注意点すら存在するのである.

本稿では,筆者が実際に体験した「お手軽に書いた自前スクリプト」を個人所有のPC上で動かす恐ろしさを後人のために記す.

目次

できごと

2020年2月某日.

筆者はTA業務の円滑化のために,多数のファイルをTeXを中間ファイルとしてPDFへと変換する作業を行っていた.
また,夜中寝ている間に変換作業が終わるように,シェルスクリプトを書いて変換を自動化していた.

研究室へ向かい,変換したPDFファイル一式を他のTAと共有しようとしたときに問題が発覚した.
...PDFファイルのすべてが,USBメモリなどの別の場所にコピーできなくなっていたのである.

もちろん,ファイルのパーミッションはすべて確認したが,正常に読み書きできる状態であったし,USBメモリの容量不足なんてこともなかった.

「ドウシテ?」「ナンデ?」
狼狽する声が自分の周囲にしか存在しない虚空へと吸い込まれていった.

幸いにしてPDFファイルはすべてiCloud Drive上にアップロードされていたため,そこからデータを受け渡すことができたものの,原因解明と復旧のためにその日の時間は虚無と化したのであった.

原因

データのサルベージに役立ったiCloud Driveは命の恩人のようにみえる. しかし,その実はコピーできない問題を引き起こした張本人であった.

自分が書いたシェルスクリプトは,変換のための中間ファイルを大量に作成し,変換後にそれらをすべて消去していた. その際に,iCloud Drive上に中間ファイル一式を保存していたため,今回の悲劇が起こったのである.

iCloud Driveは手元のマシン側でファイルの生成,変更および削除を監視して,それら変更点をトランザクションとして保存し,順次サーバとの同期を取っている. そんな中で,もしも瞬時に大量のファイルが生成され削除されることが何度も実行されるとどうなるであろうか. iCloud Driveは大量のトランザクションを抱えることになり,それらの同期処理を確実に実行しようとする. しかし,ネットワークの帯域やiCloud Driveサーバの処理能力により,大量のトランザクション実行には時間がかかる. 一方で,手元のマシン側に保存できるトランザクションにも限りがあるため,手元のマシン側ではトランザクション発生を抑える必要が生じる. 結果として,ファイルのコピーや移動など新たにトランザクションが生じる動作が制限されたと考えられる.

解決策

今回の問題はクラウドと同期されたディレクトリ内部に一時ファイルを生成したことが原因である. したがって,一時ファイルを生成する先を同期されないディレクトリ内部に生成すれば回避できる.

一時ファイルを生成する先として適切なディレクトリがUNIX/Linux系システムには存在する. それが,/var/tmp/ディレクトリである(似たディレクトリに/tmp/があるが,一部のシステムではスワップ領域として使うらしいので避けたほうがよい). この中に中間ファイルを生成するようにスクリプトを書き換えれば良い.

ただし,複数のジョブで同時にスクリプトを動かすことを考慮して中間ファイルが衝突しないように工夫する必要が生じる. その場合にはmktempコマンドを用いると良い.

© 2018-2020 urushiyama | Powered by Hugo with HUCORE theme.

Privacy Policy  |  LICENSE