Linux コマンドの定期処理で実行漏れを見つける:件数・送信内容・実行環境の確かめ方

Linux コマンドの定期処理で確かめたかったのは、実行結果の中身

TechAthletesでは、自社のサービスを作る中で、サイトの更新・計測・投稿を毎朝の定期処理で回している。今回取り上げるのは、2026年9〜10月に記録した、Linuxやシェルのコマンドの書き方に関する実測だ。作業機はmacOS、シェルはzshで、送り先のレンタルサーバはLinux。SSHで接続し、定期実行にはlaunchd・cronを使っていた。

やりたかったことは、一覧にある対象を処理し、必要なファイルを送り、その日の計測や投稿を進めることだった。ところが、コマンドが実行されたように見えることと、予定した仕事が終わることは一致しなかった。

記録した9件には、最後の対象だけが処理されない、コミットは成功するのに説明文の一部が消える、計測に必要な値が空のまま進む、といった症状があった。404やタイムアウトなどの症状も含まれるが、記録では、いずれも処理全体がエラーで止まる形では捉えられなかった。

そこで確認の対象にしたのは、成功したように見える表示だけではない。処理した件数、実際に送ったURL、送り先に展開されたファイル、動いている定期処理の接続条件だった。

「0件」という結果を、処理した件数と突き合わせる

2026年10月15日には、一覧を読む処理で最後の1件が抜けた。同じ日に2回起きている。使っていた書き方は次のものだ。

while read -r x; do …; done < list.txt

一覧を作る側が、末尾に改行を付けずに書き出していた。最後の行でreadがEOFを返すため、その行の処理に入らなかった。結果として、検査が1件抜けたまま「0件」と表示された。

この表示だけでは、対象をすべて検査した結果なのか、検査されなかった対象が残っているのかが分からない。今回の修正では、処理件数を必ず出し、期待する件数と突き合わせるようにした。書き出す側では末尾に改行を付け、ループはPython / Nodeで回す方針にした。

2026年10月には、一覧を回しながらSSHでサーバのコマンドを実行する処理でも、途中から対象が抜けた。こちらはsshが標準入力を読み、1周目で一覧の残りを消費していたため、2周目以降が走らなかった。ループ内のsshに< /dev/nullを付ける書き方に直した。

どちらも一覧を扱う処理だが、確認された原因は異なる。末尾の改行を直すことと、SSHの標準入力を切り離すことは、それぞれ必要な修正だった。そのうえで、一覧の件数と処理件数を照合する確認は、両方の実行漏れを点検する軸になった。

変数を含むコマンドは、実際に渡った文字列を見る

2026年9月27日には、APIのURLを変数で組み立てた際に404が返った。zshで使っていた文字列は次のものだった。

"properties/$ID:runReport"

zshはこの中の$ID:rを、拡張子を取る修飾子として解釈した。その結果、URLが…unReportになっていた。症状だけを見ると、単体のcurlは通るのに、ループの中でだけ壊れるように見えた。

修正は、変数を波括弧で囲むことだった。

"${ID}:runReport"

また、実際に送ったURLをcurl -wで出して確かめるようにした。コード上で意図したURLと、送信時のURLを照合するためだ。

同じく2026年9月の自動出荷処理では、echo "$VAR)"のように、変数の直後に全角文字を続けた書き方が問題になった。全角文字が変数名の続きとして読まれ、処理が一度も動いていなかった。bash / zshでは${VAR}の形に直した。

2026年10月8日には、コミットメッセージ内のバッククォートが原因となる問題も2回記録した。ダブルクォートで囲んだメッセージにコードをバッククォート付きで書くと、zshがその中身をコマンドとして実行し、該当する語がメッセージから消えていた。コミット自体は成功するため、完了表示だけでは欠落を捉えられなかった。

この処理では、クォート付きのヒアドキュメント<<'EOF'を使ってメッセージをファイルに書き、git commit -F <ファイル>で渡す方法に変えた。確認すべき結果には、コマンドの成否だけでなく、保存された文章も含まれていた。

定期実行の環境と、配布後のファイルまで確かめる

2026年9月7日、定期処理からAIのCLIを呼んだ際には、引数でプロンプトを渡していたにもかかわらず、標準入力の追加入力を待っていた。7分間無出力のまま止まり、記録された終了状態はexit 144だった。修正では< /dev/nullを付け、経過ログのstderrと回答のstdoutを混ぜないようにした。

2026年9月28日には、launchdから毎朝呼んでいたgcloudが見つからず、空の値で処理が進んだ。その日の計測は取れなかった。launchdのPATHが最小限だったため、コマンドは絶対パスで呼ぶように変更した。確認には、次の実行環境を使った。

env -i HOME=$HOME PATH=/usr/bin:/bin

対話シェルで動いたことだけでは、定期処理で動くことの証明にならない。今回の記録では、標準入力とPATHが、実行場所による違いを確かめる項目になった。

接続先の条件も同様だった。2026年9月13日、ポート指定なしのssh hostでは、22番が閉じているサーバへの接続がタイムアウトした。「サーバ障害」と判断して2時間待ったが、その間も定期処理は別のポートで成功していた。この経験から、接続できないと判断する前に、動いている処理のログで実際のポートを見ることにした。

配布では、転送後のファイルも確認対象になった。2026年9月30日、macOSからtar c … | ssh host 'tar x'でファイルを送った際、拡張属性が._ファイル名という別ファイルとして同梱された。送り先は中のファイルをすべて読むディレクトリで、それがPHPとして読まれ、約2分間、全サイトの出力の先頭にバイナリが出た。

修正ではCOPYFILE_DISABLE=1とtar --no-xattrsを使い、展開後にサーバ側でfind . -name '._*' -deleteを実行した。さらに、送信後のmd5の照合と、._*が0件であることを確認した。転送を実行したという記録に加えて、送り先の内容を確かめる手順を置いた。

業務に置き換えると

今回の記録から、定期処理・バッチ・サーバへの配布を点検する項目は、次のように整理できる。

  • 一覧を回す処理は、処理した件数を出し、一覧の件数と一致するかを見る。「0件」などの結果と、検査を実行した件数を合わせて確認する。
  • ループ内でSSHや対話できるツールを呼ぶ場合は、標準入力を/dev/nullにしているか確かめる。一覧の読み取りや追加入力待ちが、処理に影響していないかを見る。
  • 定期処理は、本番と同じ最小限のPATHで一度通してから登録する。対話シェルでの実行結果だけで判断しない。
  • macOSからLinuxへファイルを送る場合は、送り先に._*が混ざっていないか確かめる。今回の配布では、md5の照合も行った。
  • 変数の後ろに文字が続く場合は波括弧で囲む。URLを組み立てる処理では、実際に送った文字列も出して照合する。

この記事は、TechAthletes が自社のサービスを作る中で記録した実測をもとに書いています。業務への導入のご相談は 仕事の窓口 で受け付けています。

✨ Claudeエージェントを複数走らせるならAgent Desk
Terminal tile manager for macOS。全ソース付き $10 買切り。
Agent Desk を見る →

投稿者 TechAthletes 編集部

TechAthletes は、AI・クラウド・開発ツールの技術記事を公開しているメディアです。記事内の商品リンクには広告(アフィリエイトリンク)が含まれます。

コメントを残す

メールアドレスが公開されることはありません。 ※ が付いている欄は必須項目です

Click to listen highlighted text!