• ベストアンサー

ファイルの最後の行から表示させる(最新情報を5回分だけ表示)

ファイルの最後に1行追加し、6行以上になるとファイルの先頭を1行削除。 表示は最後の行から行うスクリプトを作りたいのです。 新しい情報を5回分だけ表示する様にしたかったのですが、余りにも力技なのでもう少しスマートにやる方法を教えてもらえませんか? ----sort.txt---- 1a 2b 3c 4d ---------------- #!/usr/bin/perl $fname = "sort.txt"; print "Content-type: text/html;\n\n"; $aaa="5e"; open(OUT, ">>$fname"); flock(OUT, LOCK_EX); print OUT "$aaa\n"; flock(OUT, LOCK_NB); close(OUT); open(IN, "$fname"); $cnt = "0"; while($line = <IN>){ $a[$cnt] = "$line"; $cnt++; } close(IN); if($cnt > 5){ open(OUT, ">$fname"); flock(OUT, LOCK_EX); $cnt = "0"; while($cnt < 6){ if($cnt > 0){ print OUT "$a[$cnt]"; } $cnt++; } flock(OUT, LOCK_NB); close(OUT); } $cnt = "0"; open(OUT, "$fname"); @buff = <OUT>; close(OUT); foreach $line ( reverse @buff ){ $cnt++; print "$line<br>\n"; } exit();

  • Perl
  • 回答数3
  • ありがとう数3

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

  • ベストアンサー
  • arcsin
  • ベストアンサー率70% (28/40)
回答No.1

flockによる排他制御部分は省略します. #!/usr/bin/perl print "Content-type: text/html;\n\n"; my $fname = "sort.txt"; my $aaa = "5e"; my @list = (); #一旦配列に読み込み open(IN, "$fname"); @list = <IN>; close(IN); # 末尾に要素追加 push(@list, $aaa); # 6行以上なら先頭を削除 # $#list は配列の最後の添え字を表すので # $#list+1 は配列のサイズ = 現在の行数 if($#list+1 >= 6) { shift(@line); } #保存 open(OUT, ">$fname"); print OUT @list; close(OUT); #表示(@listの使いまわし) foreach(reverse @list){  print("$_<br>"); } exit; ----------- ですかね。一度配列に読み込んじゃってから追加削除操作をしたほうがスマートかなぁと思います。

meikenpochi
質問者

お礼

arcsinさん、回答ありがとうございます。 配列の方が分かりやすいですね、ありがとうございました。

その他の回答 (2)

回答No.3

微妙に気になるのですが、 データファイルは常に最大5行なのでしょうか? >新しい情報を5回分だけ表示する様にしたかったのですが は、例えば100行から5回分だけなのか、 それとも5行から5回分(つまり全部)なのかが気になります。 (別の方法でデータが増えたりするなどして) #一行追加と一行削除 push @list,$newline; shift @list if scalar(@list)>5; 色々あると思います。 $#data使ったりとか…。 #表示 foreach (reverse @list){   print "$_\n"; } ごく普通に? 仮に5行止まりでなくて例えば100行中5行表示だとしたら、 #表示 foreach (reverse @list[-5..-1]){   print "$_\n"; } とでもすることになるのでしょうか。 読みにくい気もしますけれど。 データ量が多くないのであれば、 一括で配列に読み込んで処理すると楽で、かつ読みやすいと思います。 あとはループ変数なるべく使わないようにすると 見た目がスマートに?見えるかもしれません。

meikenpochi
質問者

お礼

natsuki_tkさん、回答ありがとうございます。 >データファイルは常に最大5行なのでしょうか? 常に最大5行にする様にファイルを編集する様にしたいと思っています。一括で配列に読み込んで処理する方法が良いですね。

  • osamuy
  • ベストアンサー率42% (1231/2878)
回答No.2

最初から新しいものを先頭に置く形でsort.txtに書き込むようにしては。こんな感じ; use strict; use Fcntl qw( :flock ); sub rec($) { my $fname = 'sort.txt'; open( F, '+<'.$fname ) or die '?! ', $fname, ' - ', $!, ','; flock( F, LOCK_EX ) or die '?! ', $fname, ' - ', $!, ','; my @recs = <F>; pop @recs; seek( F, 0, 0 ) or die '?! ', $fname, ' - ', $!, ','; truncate( F, 0 ) or die '?! ', $fname, ' - ', $!, ','; print F $_[0]; print F @recs; close( F ) } 最初に、sort.txtに5行分空行をいれとく必要があります。ここの部分がちょっと危険な仕様と感じたなら適宜防衛してください。

meikenpochi
質問者

お礼

osamuyさん、回答ありがとうございます。 短くて、綺麗ですね。

関連するQ&A

  • 新しいログの書き込み

    新しいログを追加で上に書き込む方法はどのようにしたらよいのかアイディアがありません。 ご教授願います。 if($mode eq "html"){ flock(FH, LOCK_EX); open(FH,"${datafile}"); @html = <FH>; close(FH); flock(FH, LOCK_NB); $html = join('',@html); @html = split(/$chtml/ , $html); $html[1] = $data; $html = join($chtml,@html); flock(FH, LOCK_EX); open(FH,">$datafile"); print FH $html; close(FH); flock(FH, LOCK_NB);

  • レコードの書込み判断

    ファイルを読込み、読込まれたレコードの39桁目が0であれば出力という判断を下記のコーディングに追加したいのですが、どのように記述すればよいでしょうか? if(open(OUT,">$year$mon$mday$csv")){  for my $fname (sort @dirs){   if(open(IN,"$fname")){   my @lines = <IN>;   print OUT @lines;   close(IN);   }  }  close(OUT); }

  • ログファイルの指定行に書込み

    open(IN,"$log") || &error("Open Error"); @data = <IN>; close(IN); while (100 <= @data) { pop(@data); } open(OUT,">$log") || &error("Write Error"); print OUT "$in{'id'}<>$in{'comment'}\n"; print OUT @data; close(OUT); ログにはID、時間、コメントが登録されています。 送信データの中に、ログに登録済みのIDがある場合には、そのIDのある行のみを書き換えたいのですが、方法がどうしてもわかりません。 $logに記録されるIDの順番は以下のようにランダムです。IDに登録される文字列は1からの数値のみです。 52<>コメント 120<>コメント 35<>コメント 8<>コメント 2<>コメント 19<>コメント 85<>コメント よろしくお願いいたします。

    • ベストアンサー
    • Perl
  • cgiログファイルの書き込みに余計なスペースが入る。

    ---------- #ここでログファイルに書き込みを行う。 open(FH,">>log.log"); print FH"ID=$ID&COUNT=$COUNT\n"; close(FH); #ログファイルをさらに開く。 open FILE, "<log.log"; flock(FILE,2); @log = <FILE>; flock(FILE,8); close FILE; ログファイルを並び替えてその順番で書き込み。 $gyou = @log; @sort=sort{(split(/&/,$b))[1] cmp (split(/&/,$a))[1];} @log; print "<FONT COLOR=RED>@sort</FONT><BR>\n"; open(FILE2, ">log.log"); print FILE2"@sort"; close (FILE2); ---------- というように行っていますが、一番最初のID=01&とかの前に半角スペースが入ります。 下の行に行くほどスペースが増えます。 どこが原因でしょうか?

    • ベストアンサー
    • Perl
  • CSVの条件出力について

    ディレクトリー内のCSVを1ファイルにするルーチンで、現在46カラム目から3桁が"000"なら出力としている判断を、5項目めが"000"ならに変更したいのですが、どのようにすればよいでしょうか? 現在の記述は下記の通りです。 if(open(OUT,">$path/$year$mon$mday$csv")){ for my $fname (sort @FTPlist){ if(open(IN,"$path/$fname")){ while (<IN>) { $sip = substr($_,46,3); if ($sip == "000") { print OUT "$_"; } } close(IN); } } close(OUT); }

    • ベストアンサー
    • Perl
  • 複数のCSVを1つのファイルにまとめる

    リモートからダウンロードしたCSVファイルをひとつにまとめる処理をしています。 ダウンロードするリストファイルとCSVファイルのダウンロードはできたのですが、最後にダウンロードしてきたCSVファイルをひとつにまとめるところがうまくいきません。 こちらの過去ログから下記記述してみたのですが、うまくいきません。 if(open(OUT,">$path/$year$mon$mday$csv")){      for my $fname (sort @dirs){        if(open(IN,"$path/$fname")){          my @lines = <IN>;          print OUT @lines;          close(IN);        }     }     close(OUT);   } for my $fname (sort @dirs){の記述で、Unrecognized characterといったエラーが出てうまくいきません。 項目の設定に誤りがあるのでしょうか?perl初心者でよくわかりません。 $fnameや@dirsはどのように設定すればいいのでしょうか?

    • ベストアンサー
    • Perl
  • 画像とtxtファイルの表示

    現在CGIでtxtファイルが表示されるように print "Content-type: text/html; charset=euc-jp\n\n"; $count = 0; $viewline = 1; open(IN, "A.txt"); while(<IN>){ if($count == ( $viewline - 1)){ $line = $_; last; } $count++; } close(IN); print "$line\n"; としています。 ここでさらに画像も一緒にCGIで表示させたいのですが、そうゆうことはできるのでしょうか? できるのであれば教えて頂きたいです。調べてみたのですがなかなか見つからなくて・・・。 よろしくお願いします。

    • 締切済み
    • CGI
  • ログの一部を消す Perl

    ログの一部を消すPerlを考えています。 ここではソースを短くするために、ログの一部を消し去って ログファイルに上書きするデータは $deta だけだとすると open F, '+<a.log'; flock F,2; $deta = <F>;//実際はここでもっと処理 truncate F,0; seek F,0,0; print F $deta; close F; と、 open IN, 'a.log'; flock IN,2; open OUT, '>a.log'; flock OUT,2; $deta = <IN>;//実際はここでもっと処理 print OUT $deta; close OUT; close IN; の2つを考えました。 上のように 読み込み と 書き込み を同時にやった方がいいのか 下のように分けてやった方がいいのか教えてください。 ロックは flock を使って、普通レベルのロックが できるぐらいでいいと思っているんだけど、 この flock の書き方でおかしいところがあれば 教えてください。

    • ベストアンサー
    • CGI
  • 初心者で、困っています。(文字化け)

    すみません、すごく初歩的なことで困っています。 本を見ながら、下のようなものを書いたのですが、 出力すると、文字化けをしてしまいます。ウィンドウズの環境で、Perlは5.8を使い、読み込みのテキストはUnicodeです。どのようにすれば、文字化けをしないで、読み込めるのでしょうか。 open ( IN , "LBa3_00028.txt" ) or die; open ( out , ">out.txt" ); while ( $line = <IN>){ print out "$line\n"; } close(out); close(IN);

    • ベストアンサー
    • Perl
  • perlでCSVをソートする方法について

    perl初心者です。いつもありがとうございます。 perlでcsvファイル(1行のカラム数は200)、総行数は約3万行のファイルを37番目のカラム(-25以上25未満の数値データ)で降順ソートしその値によって行数がだいたい均等になるよう3分割し、2番目のカラムに文字でも数字でもよいのですがその4つのグループごとにフラグ(例えば1,2,3)を入れたいと思ってます。グループ化については境目の37番カラムの値は重複している場合が多いと思うのですがその場合は下(別に上でもかまいません)に入れるものとします。 ソートロジックは過去の質問を参照して理解しましたがグループ化しフラグを入れるルーチンがうまく作れません。下記のように作ったのですがこの先同じことを何度もやらなくてはならないので先に進めません。どなたかお助けください。最終的にやりたいことはカラム37でグループ化→カラム2にフラグを立てる、次にカラム2とカラム38(-25から0までの数値)でソートし同様に同じ行数になるようにグループ化→カラム3にフラグを立てる、さらにカラム2とカラム3とカラム39(-25以上25未満の数値データ)でソートし・・・同様に繰り返し最終的に1グループが100件(行)~150件(行)になるようにしたいのです。つまり約3万件のデータを3*4*2*4*2=192分割(5列の値で分類)したい、そしてどのような範囲で分割したかという情報も得たいのです。 use strict; use warnings; use utf8; use Encode; binmode STDOUT, ':encoding(utf-8)'; my $dir = './data'; # 処理するディレクトリ my $motoFile = 'customer.txt'; # もとファイル open my $fh, '<:encoding(cp932)', "$dir/$motoFile" or die 'ファイルが開けません。',"$!"; my %sorted; while (my $line = <$fh>) { my $key = (split /,/, $line)[37]; push @{$sorted{$key}}, $line; if (@{$sorted{$key}} == 1000) { open OUT, '>>:encoding(cp932)', "$dir/$key.tmp" or die "Can't open: $!"; print OUT @{$sorted{$key}}; close OUT; @{$sorted{$key}} = (); } } open OUT, '>:encoding(cp932)', "$dir/out.txt" or die "Can't open: $!"; foreach my $key (sort { $b <=> $a } keys %sorted) { if (-e "$key.tmp") { open IN, '<:encoding(cp932)', "$dir/$key.tmp" or die "Can't open: $!"; print OUT while <IN>; close IN; } print OUT @{$sorted{$key}} if @{$sorted{$key}}; } close OUT; #↓↓↓↓ここからフラグを作成するルーチン # 行数を調べ3つに分けるルーチン my @colum37; open IN, '<:encoding(cp932)', "$dir/out.txt" or die 'ファイルが開けません。',"$!"; my @in = <IN>; close IN; my $gyousuu = scalar(@in); my $amari = $gyousuu % 3; if ($amari == 0) { my $groupGyousuu = ($gyousuu-$amari)/3; print "総行数は$gyousuu","で、1グループの行数は$groupGyousuu","ほど、余りは$amari\n"; # あまりが0の時、group1は@inの0行 ~$groupGyousuu-1行まで #         group2は@inの$groupGyousuu行 ~$groupGyousuu*2-1行まで #         group3は@inの$groupGyousuu*2行~$groupGyousuu*3-1行まで foreach my $num (1..2) { push @colum37, (split /,/, $in[$groupGyousuu*$num])[37]; # これは境目の先頭の37番目 } print "@colum37\n"; #これでここまでは完成、分けるべき値がこの配列に入っている。 open OUT, '>:encoding(cp932)', "$dir/out.txt" or die "Can't open: $!"; foreach my $line (@in) { my @line = split /,/,$line; if ($line[37]>=$colum37[0]) { $line[1] = 1; }elsif ($line[37]>=$colum37[1] and $line[37]<$colum37[0]) { $line[1] = 2; }elsif ($line[37]<$colum37[1]) { $line[1] = 3; } $line = join (',',@line); print OUT $line; } close OUT; } elsif ($amari == 1) { この後未作成

    • ベストアンサー
    • Perl

専門家に質問してみよう