
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個しか出力されませんでした。
子プロセスはどこへ行ってしまったのでしょうか。
この例題は私の理解力では意味不明です。
誰か分かりやすく教えてください~~
No.2ベストアンサー
- 回答日時:
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で使う分にはうまく動作するのかも知れませんが、
シェルのコマンドから実行するには工夫が必要ですね。
panda-373さん、ご返信ありがとうございます。
よく分かりました。
私がまたしても早とちりな質問をしていたということが・・・
このコードは、あくまでプログラムの一部として掲載されていたのだと思います。
恐らく前ページの最後の3行の前にこのコードを書けという指令だったのだと今、理解しました。
前ページの最後の3行とは
print $q->header( "text/plain" );
print while <PIPE>;
close PIPE;
というものです。
先ほどの例題のコードにこの3行を追加したら、ちゃんと動きました。
なるほど、このコードでは親プロセスは何の役もしていないと思っていたら、
ちゃんと最後で読み書きしていたのでした!!
No.7
- 回答日時:
確かに「を~」で始まったら意味不明ですけど$$は自分のプロセスIDなので、
(自分のプロセスID)を起動できなかった
というのもやっぱり意味が通らないということでは同じだと思います。
execに失敗したというのならまだわからないでもないですが。
sakusaker7さん、この例の場合は、
自分のプロセスをフォークできませんという風になるので、
私としては意味が通るように思います。
だけどひょっとしたらここには何か別の変数を書きたかったのかもしれませんね。
真実は記者(または訳者)のみぞ知るといったところでしょうか。
ともあれ、どうせブラウザーにはdieのメッセージは表示されませんし、
記者自身の実行環境でもdieの行が実行されることは、なかったのでしょう。
ここの行はフォークが使えない読者のための配慮だと思うので、
私の環境では、この1行を丸々取っ払ってしまっても、全然問題ないのではと思いました。
No.6
- 回答日時:
>そうすると今度は"を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?)
何でエラーになったのかの手がかりになります。
スミマセン私が理解不明と思ったのは、
"$をforkできません!"
の文字列の先頭の$を後尾の!の前へ移動して
"をforkできません$!"
としてしまうと、エラーメッセージの主語がなくなってしまうということです。
ですので、今はANo.4:kumozさんの予想と同じく、
"$$をforkできません!"
としたかったのではと思っています。
No.5
- 回答日時:
> 他にも、dieの引数となっている"$をforkできません!"という文字列も私には理解できません。
Unix に詳しくないのでよく分かりませんが、$ は $$ (プロセス ID) の誤りではないかと思うのですが?
なるほどkumozさんの予想だと、
die "$$をforkできません!"となるわけですね。
Perlでも、シェル同様に$$はプロセス番号を記憶する変数だそうですよ。
私のマシンでは、どうやってこの例題のdieの行を実行させようか検討もつかないため、
die "$$をforkできません!";
を単独で書いてみました。
23775をforkできません! at ./try line 5.
のように、きれいなメッセージになりました!!
No.4
- 回答日時:
> exec FIGLET, $string or die "figletへのパイプを開けません: $!";
書籍に誤植があるようです。書籍の前のページに次の行があります。
my $FIGLET = '/usr/local/bin/figlet';
kumozさん、貴重な情報をありがとうございます。
私も薄々感じてはいました。
やはりそうですよね。
FIGLETなんてコマンドは私のマシンには入っていないので、
ここは恐らく前のページで設定している$FIGLETを書きたかったのでしょう。
他にも、dieの引数となっている"$をforkできません!"という文字列も私には理解できません。
この先頭のドルマークは後尾のびっくりマークと合体させて"$!"としたかったのではとも感じています。
しかし、そうすると今度は"をforkできません$!"という、もっと意味不明の文になってしまうのです。。。
No.3
- 回答日時:
> 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;
}
}
t-okuraさん、ありがとうございます。
理解できました。
子プロセスがどんなにprintを実行しようが、画面には表示されないはずです。
子プロセスの出力先は標準出力ではなくパイプとなるよう私が変更していたのですものね。
またまた私の間抜けのせいで3名ものウィザードを召還してしまったことを、ここにお詫びします。
私がどのような間抜けをしたかはANo.2:panda-373さんのお礼欄へ記載しましたのでご覧ください。
No.1
- 回答日時:
とりあえずあなたの使っているOSなんぞを明確にしていただけますか?
> どうも最後のfigletの行が実行されていないようなのです。
どういう動作をしているのでしょうか?
何も出力されない、エラーメッセージもなし。ですか?
sakusaker7さん、お早いご返信をありがとうございます!!
OSはRed Hat Linux8.0で
Perlも、これに最初から入っていたものです。
このコードを実行しても何も出力されず、すぐシェルに戻ってしまいます。
エラーメッセージもないのです!!
上の例のopenとdieの間の行にprint(0);を挿入しても0が1個しか出力されないため、
フォークが発生していないのでは!!と考えています。
何か分かりますでしょうか??
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- その他(プログラミング・Web制作) atcoder python コードへの助言 2 2022/08/12 15:31
- Visual Basic(VBA) エクセルのマクロについて教えてください。 2 2023/07/15 15:48
- Excel(エクセル) マクロでテキストファイルを読み込んだ際の最終セルにデータと改行が含まれる問題の改善方法 2 2022/03/25 16:50
- CGI htmlからパラメータで、cgiに渡したい。 1 2023/02/06 16:15
- C言語・C++・C# C言語のファイル入力が分かりません 2 2022/05/22 06:35
- PHP PHP ページング データベース 1 2022/06/16 10:30
- JavaScript 初心者です。gulpでコンパイルができないので教えてください! 1 2023/05/17 17:07
- その他(プログラミング・Web制作) 【Python初学者】以下コードについて教えていただきたいです 4 2023/04/19 13:01
- その他(プログラミング・Web制作) python 気象データの取得 2 2023/06/20 23:54
- Excel(エクセル) excelvbaのenableeventsについて 3 2022/08/30 11:20
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
Perlでpopen()的なものを使って...
-
`ls`標準出力はどこにいった?
-
LinuxにおいてのPerlのプログラ...
-
Excelシート内セル記述の違いに...
-
ActivePerlでWindows上のパスを...
-
エラー画面の制御?
-
初歩的な質問ですがよろしくお...
-
サブルーチンを使った再帰的な...
-
perl で 64ビットint を扱うには?
-
PadWalkerのインストールの仕方
-
QuickTime Authoringモジュール...
-
フォーム内のテキストボックス...
-
ApacheがPerlを作動してくれな...
-
win32なモジュールでファイルを...
-
msgboxの表示
-
PerlでIPアドレスを取得する方法
-
【vba】フォームに書いてあ...
-
LCD ディスプレイを Raspberry ...
-
Excel VBAで、ユーザーフォーム...
-
エクセルVBA 時間のカウントダ...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
AIX6でファイルのタイムスタン...
-
時間がかかり過ぎたプロセスを...
-
LinuxにおいてのPerlのプログラ...
-
flockの挙動がおかしい。。。
-
実行中のcpan processを終了さ...
-
open MAILでの"|"
-
マルチスレッドとマルチプロセ...
-
Perlの処理待ちコマンド
-
system関数とqx演算子の違いに...
-
perlスクリプト内でシェルコマ...
-
Active Directoryでグループに...
-
Parallel::ForkManagerについて
-
Perlでpopen()的なものを使って...
-
ハマったので助けて~。Apache...
-
my $pid = open PIPE, "-|";の...
-
Perlでexitコードを取得する方法
-
perlでゾンビプロセスが発生
-
例外処理のフローチャートの記...
-
Excel VBAでリンク切れをチェッ...
-
Excel VBAで、ユーザーフォーム...
おすすめ情報