恥知らずのウェブエンジニア -web engineer, shameless

これは一歩を踏み出すことができない者たちのブログ

プログラム内でコマンド実行した時にnull文字にしてやられる!

業務中ログローテートのプログラムを作った時にハマったのでメモわさ!


アクセスログなどとは別の、サービスとしてのログが、
プロジェクトのvar/以下にlog_*****_20140101などのように保存されていく。

var/以下に、さらに○○_log/のようなディレクトリもありそれぞれのログが存在。


そして、今回作ったログローテートのプログラムはざっくり下記のようなもの。

1,対象のログディレクトリを検索

$find_cmd = '/bin/find ' . $project_log_dir . ' -maxdepth 1 -type d | grep -v "old"';
exec($find_cmd, $res_find);


2,検索結果からそのディレクトリ内にあるファイルを列挙(フォーマットはファイル名+最終更新日時)

foreach ($res_find as $target_dir)
{
	exec('/bin/find ' . $target_dir . ' -maxdepth 1 -type f -print0 -printf ",%T@\n" | grep --binary-files=text -v "\/\."', $tmp_files);
}


3,列挙されたファイルから,最終更新日時が前日以前のものをgzip後にoldディレクトリに移動

foreach ($tmp_files as $row)
{
	$arr		= explode(',', $row);
	$file_path	= $arr[0];
	$time_stamp	= $arr[1];
	//今日以前のログをgzip,mv
	if ($time_stamp <= $today)
	{
		$gzip_cmd	= 'sudo /bin/gzip -9 ' . $file_path;
		$mv_cmd		= 'sudo /bin/mv ' . $file_path . '.gz ' . $archive_dir;
		exec($gzip_cmd);
		exec($mv_cmd);
		echo $gzip_cmd . "\n";
		echo $mv_cmd . "\n\n";
	}
}


4,これをcronで1日1回実行!

の流れだけなのですが、実行すると下記のエラー・・・

mv: missing destination file operand after

移動先のディレクトリ指定がおかしい的な内容なのですが、
明らか移動先のディレクトリは存在してるし、権限も問題ない!
試しにechoで出した、文字列を実行してみると、正常に動作する!
コマンドもフルパスでやってるし、gzipに時間がかかるの・・・?!
バックグラウンドで実行されてるとかあったりするの?とか謎に悶々・・・・


で試しにechoをvar_dumpに変えるとヒントが・・・
ファイル名の中に"\000"なる文字が入っているっぽい。
ぐぐってみるとnull文字とのこと。
なんでそんなん入ってんだよ!誰だよそんなトラップ仕組んだのは!!


ぼくでした。


findのオプションで-print0 ファイル名+日付にしたくて入れてました。

find 
-print
真を返す。ファイル名をフルパスで標準出力に表示し、各ファイル名に改行文字を付加する。
-print0
真を返す。ファイル名をフルパスで標準出力に表示し、各ファイル名にヌル文字を付加する。このオプションを用いれば、 find の出力を処理するプログラムにおいて改行文字を含んだファイル名を正しく解釈できるようになる。


なので、ファイル名の最後のnull文字を削除するよう修正したら上手くイキマシタ。

$file_path	= rtrim($arr[0]);


感謝致します。

f:id:ogataka50:20140115135850j:plain