• ベストアンサー

while (<STDIN>) {・・} の意味。

 while(<STDIN>){    ・・・  } の場合、ファイルの終わりに来ると whileループを抜けます。 しかし、ここで疑問があります。 <STDIN>はファイルの終わりに来ると undef を返しますよね? しかし、結城浩さんによると、 「Perlでは(undef)は真」となっています。 http://d.hatena.ne.jp/hyuki/20060406#undef すると、上記のループは本来終わらないはずでは、 と思ってしまうのですが・・・。 何が間違っているのでしょうか?

  • CGI
  • 回答数2
  • ありがとう数3

質問者が選んだベストアンサー

  • ベストアンサー
  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.2

ついでに補足しておくと >「Perlでは(undef)は真」 は、 「Perlでは undef は真」 の意味ではありません。 サイトでも説明されている通り、 @array = undef ; は、 @array = (undef) ; の様に評価されるということです。 これは、 $array[0] = undef; の意味です。 その時 @array をスカラーで評価すると、要素数になるので、 要素数:1、で真になります。 サイトの例で sub foo { return undef; } とされていますけど(もちろんわざと) こういう返値が配列に代入されることが予想される場合 return wantarray ? : () : undef; とすべきです。 これなら問題ないです。

white-tiger
質問者

お礼

すごく納得しました! ありがとうございます。

その他の回答 (1)

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.1

Perl では、undef は、偽です。 というか、 undef は、 数値として評価をすると0 文字列として評価をすると'' #空文字列 になり、0及び空文字列は、偽です。 ついでに ( ) # 空リストも偽です。 質問文のサイトでもそのことははっきりしています。 while(undef){ } では、ブロックが実行されないのは、質問文のサイトでも示されています。 ただ、問題となるのは、 @array = (); if(@array){ #実行されない } ですが、 @array = undef; if(@array){ #実行される } ということについて書かれています。

関連するQ&A

  • STDINの挙動がよく分かりません

    POST形式で読み込んだデータを3通りで書きだしてみました。しかしながら1番最初のファイルにしかデータは書き出されていません。 ひょっとしてSTDINはコンピュータがアクセスしてきた時の行を覚えていて、次のアクセスがあった時はそこから処理が行われるのでしょうか。それなら1度ファイルに全ての入力データを書き出した際にアクセスポイントはファイルの最後になっているから、2度目、3度目の書き出しの際はループが廻るはずがありません。 そこで書き出しまえに$-を書き出してみました。でも1度目のループを行う前から値は0。 前にファイルハンドル名など何かを付けなくては$-は死んでいるのかと思って、$=を書き出してみると60という値を取ります。でも書き出された1度目のループのファイルを数えてみると$=80なんです。何なんでしょう、この60という値は。 どうもSTDINの挙動が分からないのですが、どういう理由でこうなっているのか。どうしたら3回ループを廻すことが出来るのかご教授いただけないでしょうか。 ********************************************** #!/usr/bin/perl -d use CGI; use SR; open(OUT,'>stdin_main.txt'); print OUT $-."\n"; print OUT $=."\n"; while(<STDIN>) { print OUT $_; } close(OUT); &SR::parse_form; our $q=new CGI; print $q->header(-charset=>'utf-8'), $q->start_html(-charset=>'utf-8', -lang=>'ja-JP'), $-,"<br />\n", $=,"<br />\n"; while(<STDIN>) { print $_; } print $q->end_html; ********************************************** package SR; sub parse_form { open(OUT,'>stdin_SR.txt'); print OUT $-."\n"; print OUT $=."\n"; while(<STDIN>) { print OUT $_; } close(OUT); } 1;

    • ベストアンサー
    • Perl
  • 配列の終わりまで while

    ファイルの終わりまでループをするなら while($input = <IN>){ ・・・とすればよいかと思うのですが、 配列の終わりまでループをするにはどうしたら よいのでしょうか。 while(@test = ???){

    • ベストアンサー
    • Perl
  • STDINによるキーボードからの入力について

    初めて質問させて頂きます。 最近Perlの勉強をはじめ、perlによるネットワークプログラミングに興味が出てきたので、 自分でインスタントメッセンジャーの様な物を作ってみようと思いました。 1つのwhileループ内で、 "受信データがある場合はその内容を表示" "クライアントへの入力があった場合はその内容を送信" という動作をさせたいのですが、 <STDIN>で入力待機状態となるとループが止まるので、受信→内容表示の処理が滞ってしまいます。 while(1){ if(受信内容がある){ print "受信内容"; } if($senddata=<STDIN>){ #ここで止まってしまう為、受信表示ができない print $ソケット "$senddata"; } } 入力待ちをすれば、止まってしまうのは当たり前と言うことはわかっているのですが・・・。 過去の質問に、スレッドを利用して "受信があればそれを表示"と"入力があればそれを送信" の動作を分けている方がいらっしゃいましたが、 スレッドで分けずにこの動作を実現する事はできるのでしょうか? また、可能ならばどの様にしたら良いのでしょうか?

    • ベストアンサー
    • Perl
  • perlのdo-while文で抜け出せない 

    perlのwhile,do-while,last文に関する質問です。 1) code1のようなプログラムを作ったのですが   eでdo_whileを抜け出すことができませんがなぜでしょうか。 ---code1(eで抜け出せない)(NG)--- my $sum=0; do{  my $a=<STDIN>;  chomp($a);  $sum=$sum+$a; }while($a ne 'e'); print $sum; -------------------------------- 2) 抜け出す方法をいろいろ試していたら   while(1)にしてlastで抜けるようにすると   code2ではeで抜け出すことができるように   なりましたが、   do~while(1)にしたcode3では、  「Can't "last" outside a loop block at …」C   というエラーが発生します。   code2とcode3はwhileがdo~whileになって   条件を見る位置がループの始めか終わりの   違いだけなのに、なぜ、code2ではOKで、   code3ではエラーになるのでしょうか。 ---code2(eで抜け出せる)(OK)----- my $sum=0; while(1) {  my $a=<STDIN>;  chomp($a);  last if ($a eq 'e');  $sum=$sum+$a; }; print $sum; --------------------------------- ---code3(エラーになる)(NG)----- my $sum=0; do{  my $a=<STDIN>;  chomp($a);  last if ($a eq 'e');  $sum=$sum+$a; }while(1); print $sum; --------------------------------- よろしくお願いします。 Windows7 , ActivePerl(v5.16.3)

    • ベストアンサー
    • Perl
  • perlのwhile,連想配列についてです。

    perlの連想配列を使い "AP" => "Apple" "BN" => "Banana" "OG" => "Orange" という値を格納します。 そしてこの格納した値をキーボードからの入力で取り出します。 このように表示したいです↓↓ "好きな果物を入力してください[AP/BN/OG]" そして入力を受けるとその果物の値を返し果物の名前を表示します↓↓ "あなたの好きな果物はAppleですね" ここまではできたのですが、この格納した果物以外を入力するとwhileで格納した果物が入力されるまで"3種類から選んでください”というようにループしたいです。 この場合どのように書けばよいのでしょうか。 whileの場合andで書きたい場合はどのように書けばよいのでしょうか。 また入力には<STDIN>を使い引数はchmopで処理すると良いとアドバイスを貰いましたがchompの使い道がよくわかりません。 そちらも説明していただけると幸いです。 わかりにくい質問ですがよろしくお願いします。

    • ベストアンサー
    • Perl
  • Perl ファイルハンドルを閉じずに反映させる

    お世話になっております。 Perl(プログラミング言語)について質問です。 openメソッドで開いたファイルハンドルに print文で書込みを行った際に、ファイルハンドルをcloseせずに、 書込みを反映させる方法はありますか? 開くのはファイルではなく(他プロセスへの)パイプです。 $| を設定してもだめでした (例としては perl1.pl , perl2.pl を用意する <perl1.pl> $i; open(OUT,"| perl2.pl") while(1){ print OUT "$i" $i++  } close(OUT) <perl2.pl> while( <STDIN> ) { print $_; } のようなことをやりたいです。 上記のようなスクリプトを実行したところ、 perl1のcloseが実行されるまで反映されません。 これをcloseをせずに反映させる方法はありますでしょうか? よろしくお願いします。

    • ベストアンサー
    • Perl
  • 入力を待たずにstdinの監視をしたい(C言語)

    こんにちは.タイトルのままなのですが,c言語でstdinに何かが入力されるまで待つことなく,stdinの監視がしたいです.例えば, whileループを回してる最中に,qがstdinに入力されたらbreakするけど,あとは普通に回る,みたいな感じにしたいです.fgetc(stdin)とすると,毎回入力を待つことになるので,待たないで回る方法が知りたいです. 具体的には,以下はgnuplotにsinカーブを表示するプログラムですが,コメントアウトしてある /* if((buf = fgetc(stdin)) == 'q'){ break; } */ の部分のようにすると毎回とまってしまいます.これを,毎回入力を待たずに,qを打ったら止まるようにするにはどうするのが普通なのでしょうか. 返信おまちしております. #include <stdio.h> #include <math.h> #include <unistd.h> FILE *gp; #define omega (M_PI/2) #define A 1 #define N 10 int i; int j; double x, t; int main(void) { gp = popen(gnuplot, "w"); fprintf(gp, "set xrange [0:11]\n"); fprintf(gp, "set yrange [-3.5:3.5]\n"); fprintf(gp, "set xlabel \"x\"\n"); fprintf(gp, "set ylabel \"y\"\n"); char buf; for (j = 0; j < N*160; ++j) { usleep(5000); /* if((buf = fgetc(stdin)) == 'q'){ break; } */ fprintf(gp, "plot '-' with lines linetype 1\n"); for (i = 0; i < j+1; ++i) { t = 0.1*i; x = A*sin(omega*t); fprintf(gp, "%f\t%f\n", t/10, x); } fprintf(gp, "e\n"); } fprintf(gp, "exit\n"); fflush(gp); pclose(gp); return 0; }

  • シェルスクリプト:while文のリダイレクトはサブシェルで実行されますか

    日頃Linuxを使用している者です。手元にSolaris環境がなく検証できないためSolaris使いの方にお伺いさせてください。 お聞かせいただきたいことは次の一点です。 Q. Solaris8,9,10 のBourneShellは従来どおり、while文でリダイレクトを使ったときは、サブシェルでまわりますか? 上記質問に至った簡単な経緯を申し上げます。 実は、Linuxの/bin/ash(BourneShell相当)スクリプトで while文でリダイレクトしたところ、ループ内の変数がwhileの外でも参照できました。本来BourneShellの場合、当ケースでのループはサブシェルで回るはずですよね。 最近のGNU BASHを始め、ASHもfor,whileのりダイレクトを使ったループもカレントシェルで動作するということでしょうか? そこで、SolarisのSHはどうなのかと思った次第です。以上宜しくお願いします。 p.s. HP-UX, AIXのSHについても情報があればありがたいです。 参考までに、Linux上の実例を記します。 ■test.ash #!/bin/ash n=0 while read line do i=`expr $i + 1` echo "$i: $line" done < $0 echo "total line= $i" ■実験してみる > ./test.ash 1: #!/bin/ash 2: 3: i=0 4: while read line 5: do 6: i=`expr $i + 1` 7: echo "$i: $line" 8: done < $0 9: echo "total line= $i" total line= 9 ← しっかりインクリメントされた変数見れてるし。最近の仕様?

  • シェルスクリプト while read lineにつきまして

    シェルスクリプトについて、各行の値を使って、更新したいと考えています。 引数を2つ持たせて、2つともファイルです。 ファイル名1には、 test1 test2 test3 のディレクトリを記載し、 ファイル名2には、 test4.txt test5.txt test6.txt のテキストを記載します。 例) 引数1 ファイル名1 引数2 ファイル名2 while read lineをどのように使ったら良いかわからないのですが、 ファイル名1を1行ずつ読み込んで、 読み込んだディレクトリをファイル名2に書かれているテキストを更新します。 具体的にやりたいと思っている内容ですが、 ・cd ファイル名1の1行目ディレクトリ ・svn up ファイル名2のテキスト ここをファイル名2に書かれている行分ループして 上記svn upコマンドを実行します。 ・ファイル名2に書かれている行分ループ完了後、 ファイル名1の2行目にかかれているディレクトリを読み込んで、 cd ファイル名1の2行目ディレクトリ ・svn up ファイル名2のテキスト ここをファイル名2に書かれている行分ループ。 という形のシェルスクリプトを作成したいと思っています。 上手く説明できないのですが、このようなことが出来るのかお教えいただけますでしょうか。 出来るのであれば、どのようにすればできるのかご教授いただけると幸いです。 宜しくお願い致します。

  • WindowsでPerlをする際,1行目の"#! ~"はどのように?

    Perlの参考書・本等ではプログラムファイルの第1行目は #! /usr/local/bin/perl という1行がよく有りますが,WindowsXPを用いている場合では,この1行をどう直せばよいのでしょうか? #! (perl.exeが存在するフォルダのパス) でよいのでしょうか? 私はWindowsXPを使っていて,この1行を使わずにプログラムを書いておりましたので,この1行の意味がよく分かりません。 ある参考書には,"#!はその行に書いたコマンドに,ファイルの残りの部分を渡して実行すると言う性質を持っている"と有りました。だから,試しにfile1.plとfile2.txtを準備し, file1.plの中身  #! (perlの存在するフォルダのパス)\perl.exe  while(<STDIN>){   print;  } file2.txtの中身  hello world として,コマンドプロンプトで file1.pl < file2.txt としたのですが正しく動作しませんでした.(perl file1.pl < file2.txt と入力した場合は正しく"hello world"となりました)

    • ベストアンサー
    • Perl