【cron】Macでcronを設定してみた

## はじめに
`cron` を触る機会があったので流れを理解するために、簡単なサンプルコードを作成して `cron` の設定をしてみました。


## 目次

- [はじめに](#はじめに)

- [目次](#目次)

- [実装フロー](#実装フロー)

- [サンプルコード](#サンプルコード)
    - [sample.php](#samplephp)

- [cronの設定](#cronの設定)
    - cronの登録
    - cronの内容
    - 登録しているcronの確認
    - logファイルを確認
    - cronの削除

- [おまけ](#おまけ)
    - cronの `*` の意味
    - logファイル出力ができず `permission denied`
    - Datetimeでエラーが起きる？

- [おわりに](#おわりに)

- [参考文献](#参考文献)
    - cron
    - シェルスクリプト
    - PHP


## 実装フロー

- 定期的に動作させたいファイルを作成( やりたいことはなにか )
- cronを登録( どのくらいの頻度で動かしたいか )

具体的に言うと下記のようなプログラムを想定しています。

- cron からphpコマンドを叩く(引数を渡してあげる)
- phpでは引数を受け取ってそれを毎分logファイルに書き込む

今回はあくまで練習なので簡単なコードを作成して動かしてみました。
現在時刻を引数として受け取っていればその **時間を整形し出力** する、なければ **「今何時？」** と出力する。

今回、定期的に動作させたいファイルはPHPで作成しました。

## サンプルコード

#### sample.php

```php:sample.php
<?php

// 引数を受け取っていれば
if (isset($argv[1])) {
    // 現在時刻を整形する
    $current_time = (new \DateTime($argv[1]))->format('Y-m-d H:i:s');
}

// 引数があるときとないとき出力先を決める
$output_file_path = '/var/log/cron.log';
$error_file_path = '/var/log/error.log';

// ログ出力をする
if ($current_time) {
    error_log($current_time . PHP_EOL, 3, $output_file_path);
} else {
    error_log('今何時？？' . PHP_EOL, 3, $error_file_path);
}

```

## cronの設定

#### cronの登録

```terminal:ターミナル
crontab -e
```

#### cronの内容

```terminal

# /usr/bin/php はｐｈｐコマンド
# シェルスクリプトであれば sh になります。
# ***のところで毎分実行の設定をしている

* * * * * /usr/bin/php [上で作成したファイルのパス]/sample.php
* * * * * /usr/bin/php [上で作成したファイルのパス]/sample.php `date '+\%Y\%m\%d\%H\%M\%S'`

```

#### 登録しているcronの確認

```terminal:ターミナル
crontab -l
```

#### logファイルを確認

想定通りの挙動を確認できました。

```log:/var/log/cron.log
2021-05-22 14:25:00
2021-05-22 14:26:00
2021-05-22 14:27:00
```

```log:/var/log/error.log
今何時？？
今何時？？
今何時？？
```

#### cronの削除

今回は練習のための設定なので最後に cron を削除していきます。

```terminal:ターミナル
crontab -r
```

削除できたか

```terminal:ターミナル
crontab -l
```

で一応確認。

## おまけ

#### ｃronの `*` の意味

| 1 | 2 | 3 | 4 | 5 | 6 |
|:-:|:-:|:-:|:-:|:-:|:-:|
| 分 | 時 | 日 | 月 | 曜日|コマンド|
| * | * | * | * | * |  |

#### logファイル出力ができず `permission denied`

実行権限、書き込み権限などがないかもしれません。
対象となるファイルの権限を変更してみたら解消されるかもしれません。

```terminal:ターミナル
sudo chmod 777 [ファイル名]
```

#### Datetimeでエラーが起きる？

`cron` でdateコマンドでフォーマットを使用するときは `%` の前に `\` をつけてエスケープしてあげることで正しい挙動になるかと思います。[(参考文献)](https://qiita.com/Kobecow/items/15f07dfe075083ff326d)

- 通常のLinuxコマンド


```terminal:ターミナル
`date '+%Y%m%d%H%M%S'`
```

- cron の場合

```terminal:ターミナル
`date '+\%Y\%m\%d\%H\%M\%S'`
```



## おわりに

簡易的に `cron` を設定してみました。
自分の環境に落とし込むと理解が捗りますね。

## 参考文献

#### cron
- [クーロン(cron)をさわってみるお](https://qiita.com/katsukii/items/d5f90a6e4592d1414f99)
- [cronの日時指定を、基礎から学ぶ（分,時,日,月,曜日の指定、◯分ごと、月末起動、など）](https://www.yoheim.net/blog.php?q=20190902)
- [cronでdateコマンドうまくいかない？](https://qiita.com/Kobecow/items/15f07dfe075083ff326d)

#### シェルスクリプト
- [シェルスクリプト: コマンドライン引数を取得する](https://maku77.github.io/linux/startup/command-line-params.html)
- [シェル: コマンドの実行結果を変数に入れる方法](https://armadillo.atmark-techno.com/blog/53/3081)
- [date コマンド](https://hydrocul.github.io/wiki/commands/date.html)

#### PHP
- [error_log](https://www.php.net/manual/ja/function.error-log.php)
- [DateTime クラス](https://www.php.net/manual/ja/class.datetime.php)
- [isset](https://www.php.net/manual/ja/function.isset.php)
- [$argv](https://www.php.net/manual/ja/reserved.variables.argv.php)