にゃーん
これまでのあらすじ
catコマンドってなんだ
複数のファイルを連結して標準出力するのがcat
コマンド。
% cat ./hoge #hogeファイルの中身を標準出力する
ほげ
% cat ./hoge ./huga ./piyo > ./xxx #ファイルを連結してxxxファイルに書き込む
% cat ./xxx
ほげ
ふが
ぴよ
% echo んー | cat # パイプで渡して引数なし
んー
% echo んー | cat - - - # - が標準入力
んー
んー
んー
要件としては、こんな感じ…?
実装
引数なしのときは標準入力のみを出力。標準入力はキャッシュする。
あと、ファイルがなかったりしたら標準エラー出力に書き込む。
fwrite(STDERR, "cat: ${f}: No such file or directory" . PHP_EOL);
文言は例によってBSD catから拝借してる。読み込めないファイルがひとつでもあったとき、終了ステータスは1
にする。
完成
#!/usr/bin/env php
<?php
namespace zonuexe\UnixCommand;
/**
* CAT command
*
* @author USAMI KENTA <tadsan@zonu.me>
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache-2.0
* @copyright 2015 USAMI Kenta
*/
if (realpath($_SERVER['SCRIPT_FILENAME']) == realpath(__FILE__)) {
$argv = isset($_SERVER['argv']) ? $_SERVER['argv'] : [];
array_shift($argv);
exit(cat($argv));
}
/**
* @return int UNIX status code
*/
function cat(array $argv)
{
$files = $argv ?: ['-'];
$failed = false;
$stdin = null;
foreach ($files as $f) {
$file = null;
if ($f === '-') {
if ($stdin !== null) {
echo $stdin;
continue;
}
$file = STDIN;
} elseif (!is_file($f)) {
$failed = true;
fwrite(STDERR, "cat: ${f}: No such file or directory" . PHP_EOL);
continue;
} else {
$file = fopen($f, 'r');
}
while (!feof($file)) {
$data = fread($file, 8192);
if ($data === false) {
break;
}
if ($f === '-') {
$stdin .= $data;
}
echo $data;
}
fclose($file);
}
return $failed ? 1 : 0;
}
感想
今回は標準入出力を扱ったり終了ステータスを扱ったり、ちゃんとUnixコマンドっぽい感じになりましたね。