アプリ版:「スタンプのみでお礼する」機能のリリースについて

CGIプログラミング第2版
233ページに掲載されているコードがうまく動きません。

my $pid = open PIPE, "-|";
die "$をforkできません!" unless defined $pid;

unless ( $pid ) {
exec FIGLET, $string or die "figletへのパイプを開けません: $!";
}

このコードは入力した文字列をアスキーアートにしてくれるものなのですが、どうも最後のfigletの行が実行されていないようなのです。
openの使い方が特殊らしく、少ない行数の割に、えらい複雑なコードだな~と感じています。
openを実行した時にフォークが発生し、最終的に子プロセスがfigletを実行してくれるはずなのですが、どうも子プロセスがいない感じがします。
例えば
fork; print(0);
こんな感じにフォークをした場合
00
のように0が2個出力されるのですが、
この例題のopenの直後に
print(0);
と記述しても
0は1個しか出力されませんでした。
子プロセスはどこへ行ってしまったのでしょうか。
この例題は私の理解力では意味不明です。
誰か分かりやすく教えてください~~

A 回答 (7件)

my $pid = open PIPE, "-|";


// パイプをオープンし、成功すれば変数"pid"に
// 親プロセスの場合は、子プロセスのPIDを
// 子プロセスの場合は、0をセットする。
die "$をforkできません!" unless defined $pid;

unless ( $pid ) {
// 子プロセスの場合(PID==0の場合)、
// exec 命令を使い、FIGLET $string を実行する。
exec FIGLET, $string or die "figletへのパイプを開けません: $!";
}

この場合、FIGLET を実行した結果を親プロセス側でREADしてやる仕組みが必要です。
以下のようなサンプルを実行すると、
my $string = "hogehoge";
my $pid = open(PIPE, "-|");
if ($pid) {
print "This is a parent process (PID=$pid)\n";
read (PIPE,$str,80);
print $str;
} else {
exec "/bin/echo", $string;
}
endif;

このような結果になります。
This is a parent process (PID=7024)
hogehoge

exec で実行した結果を、親プロセス側では
read(PIPE,$str.....); の行で読み込んで出力しています。

CGIで使う分にはうまく動作するのかも知れませんが、
シェルのコマンドから実行するには工夫が必要ですね。
    • good
    • 0
この回答へのお礼

panda-373さん、ご返信ありがとうございます。
よく分かりました。
私がまたしても早とちりな質問をしていたということが・・・

このコードは、あくまでプログラムの一部として掲載されていたのだと思います。
恐らく前ページの最後の3行の前にこのコードを書けという指令だったのだと今、理解しました。

前ページの最後の3行とは
print $q->header( "text/plain" );
print while <PIPE>;
close PIPE;
というものです。

先ほどの例題のコードにこの3行を追加したら、ちゃんと動きました。

なるほど、このコードでは親プロセスは何の役もしていないと思っていたら、
ちゃんと最後で読み書きしていたのでした!!

お礼日時:2008/04/05 20:19

確かに「を~」で始まったら意味不明ですけど$$は自分のプロセスIDなので、



(自分のプロセスID)を起動できなかった

というのもやっぱり意味が通らないということでは同じだと思います。
execに失敗したというのならまだわからないでもないですが。
    • good
    • 0
この回答へのお礼

sakusaker7さん、この例の場合は、
自分のプロセスをフォークできませんという風になるので、
私としては意味が通るように思います。

だけどひょっとしたらここには何か別の変数を書きたかったのかもしれませんね。
真実は記者(または訳者)のみぞ知るといったところでしょうか。

ともあれ、どうせブラウザーにはdieのメッセージは表示されませんし、
記者自身の実行環境でもdieの行が実行されることは、なかったのでしょう。

ここの行はフォークが使えない読者のための配慮だと思うので、
私の環境では、この1行を丸々取っ払ってしまっても、全然問題ないのではと思いました。

お礼日時:2008/04/06 13:57

>そうすると今度は"をforkできません$!"という


$! だったら特殊変数のひとつですよ。

$!

If used as a string, yields the corresponding system error
string. You can assign a number to $! to set *errno* if, for
instance, you want "$!" to return the string for error *n*, or
you want to set the exit value for the die() operator.
(Mnemonic: What just went bang?)

何でエラーになったのかの手がかりになります。
    • good
    • 0
この回答へのお礼

スミマセン私が理解不明と思ったのは、
"$をforkできません!"
の文字列の先頭の$を後尾の!の前へ移動して
"をforkできません$!"
としてしまうと、エラーメッセージの主語がなくなってしまうということです。

ですので、今はANo.4:kumozさんの予想と同じく、
"$$をforkできません!"
としたかったのではと思っています。

お礼日時:2008/04/06 11:27

> 他にも、dieの引数となっている"$をforkできません!"という文字列も私には理解できません。



Unix に詳しくないのでよく分かりませんが、$ は $$ (プロセス ID) の誤りではないかと思うのですが?
    • good
    • 0
この回答へのお礼

なるほどkumozさんの予想だと、
die "$$をforkできません!"となるわけですね。
Perlでも、シェル同様に$$はプロセス番号を記憶する変数だそうですよ。

私のマシンでは、どうやってこの例題のdieの行を実行させようか検討もつかないため、
die "$$をforkできません!";
を単独で書いてみました。
23775をforkできません! at ./try line 5.
のように、きれいなメッセージになりました!!

お礼日時:2008/04/06 11:15

> exec FIGLET, $string or die "figletへのパイプを開けません: $!";


書籍に誤植があるようです。書籍の前のページに次の行があります。

my $FIGLET = '/usr/local/bin/figlet';
    • good
    • 0
この回答へのお礼

kumozさん、貴重な情報をありがとうございます。
私も薄々感じてはいました。
やはりそうですよね。
FIGLETなんてコマンドは私のマシンには入っていないので、
ここは恐らく前のページで設定している$FIGLETを書きたかったのでしょう。

他にも、dieの引数となっている"$をforkできません!"という文字列も私には理解できません。
この先頭のドルマークは後尾のびっくりマークと合体させて"$!"としたかったのではとも感じています。
しかし、そうすると今度は"をforkできません$!"という、もっと意味不明の文になってしまうのです。。。

お礼日時:2008/04/05 20:42

> my $pid = open PIPE, "-|";



親プロセスは <PIPE> で、fork した子プロセスの(標準出力への)出力を読
みます。言い換えると、「子プロセス | 親プロセス」 のようにパイプで
つないだような(ただし、標準入力ではなく PIPE から読み込む)動作にな
ります。

> 上の例のopenとdieの間の行にprint(0);を挿入しても0が1個しか出力さ
> れないため、フォークが発生していないのでは!!と考えています。

子プロセスの出力は、親プロセスに渡されているため、表示されません。
open と die の間に下記のようなコードを挟めば、Hello World が 2行
表示されるはずです。

print "Hello World\n";
if ($pid) { # 親
while (my $pipe = <PIPE>) {
print $pipe;
}
}
    • good
    • 0
この回答へのお礼

t-okuraさん、ありがとうございます。
理解できました。
子プロセスがどんなにprintを実行しようが、画面には表示されないはずです。
子プロセスの出力先は標準出力ではなくパイプとなるよう私が変更していたのですものね。

またまた私の間抜けのせいで3名ものウィザードを召還してしまったことを、ここにお詫びします。
私がどのような間抜けをしたかはANo.2:panda-373さんのお礼欄へ記載しましたのでご覧ください。

お礼日時:2008/04/05 20:30

とりあえずあなたの使っているOSなんぞを明確にしていただけますか?



> どうも最後のfigletの行が実行されていないようなのです。

どういう動作をしているのでしょうか?
何も出力されない、エラーメッセージもなし。ですか?
    • good
    • 0
この回答へのお礼

sakusaker7さん、お早いご返信をありがとうございます!!
OSはRed Hat Linux8.0で
Perlも、これに最初から入っていたものです。

このコードを実行しても何も出力されず、すぐシェルに戻ってしまいます。
エラーメッセージもないのです!!
上の例のopenとdieの間の行にprint(0);を挿入しても0が1個しか出力されないため、
フォークが発生していないのでは!!と考えています。
何か分かりますでしょうか??

お礼日時:2008/04/05 18:29

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!