これからの季節に親子でハイキング! >>

Perl初心者です。
test.txtというファイルがあって、その中の1行目から3行目までを
出力したい場合はどうしたらいいでしょうか?

open(FILE,"test.txt") || die "Open Error.\n";
@data = <FILE>;
close(FILE);

foreach (@data) {
print $_;
}
これだと、ファイルの中身が全て出力されてしまいます。

このQ&Aに関連する最新のQ&A

A 回答 (7件)

@dataというのは配列で、1つの要素が1行になっています。


つまり、
foreach 1周目: $_ → $data[0] … 1行目
foreach 2周目: $_ → $data[1] … 2行目
foreach 3周目: $_ → $data[2] … 3行目
foreach 4周目: $_ → $data[3] … 4行目
というわけです。

やりかたはいくつかありますが、今後のことを考えると
新しくスカラー型の変数を用意してforeach内部のループ回数を数えるようにすると
勉強になると思います。

$count = 0;
foreach (@data) {
 print $_;
 # * count増加
 # * countが3になったらループを抜ける
}

for文を使って同じことをしてみるのも勉強になると思います。
    • good
    • 0
この回答へのお礼

すごくわかりやすいです!
配列の使い方、foreach文の使い方がよくわかりました!

お礼日時:2007/01/22 18:53

open(FILE, "test.txt");


while (<FILE>) {
print if 1 .. 3;
}
範囲演算子をスカラーコンテキストで評価すると「それなりに」行との比較が行われます. 整定数の場合は行番号との比較, パターンマッチングならその行でマッチするかどうかをします.
    • good
    • 0
この回答へのお礼

Perlは、さまざまな書き方があるので、
自分が一番理解しやすい文法で書こうと思いました。
ありがとうございました。

お礼日時:2007/01/25 09:03

ファイルを一度に全部読む必要はあるのでしょうか?



これまでの回答にもある通り、何行出力したかを
数えておけばいいだけの話なんですが、こういうやり方も
あるよということで。

use strict;
use warnings;
use English;

open my $fh, '<', 'test.txt' or die "open error: $!";

while (my $line = <$fh>) {
last if eof $fh or $INPUT_LINE_NUMBER > 3;
print $line;
}

close $fh;
    • good
    • 1
この回答へのお礼

行頭から3行目までのuseの部分は今まで使ったことがありません。
モジュールを呼び出してるのでしょうか?!
それらのモジュールを呼び出しているから、
$INPUT_LINE_NUMBER には、行数が入っていると判断しました。

お礼日時:2007/01/22 18:56

3番の方のようにfor文でやる場合は配列が3行以下の場合に注意ですよ、

    • good
    • 0
この回答へのお礼

どのように注意をしたらいいのでしょうか?
3番の方のやり方で、うまく表示できたのですが。。。

お礼日時:2007/01/22 18:54

foreach (@data) {


print $_;
}

の部分を

for ($i=0 ; $i<3 ; $i++) {
print $data[$i] ;
}

かな。
    • good
    • 0
この回答へのお礼

$data[$i]で、@dataを一行ずつ取り出せるのですね。
配列の理解が足りなかったようです。

お礼日時:2007/01/22 18:51

同じくPerl初心者です。


また頼りになる人たちが答えてくれるとは思うんだけど、
前に私がした質問と似てるところがあるので、参考になればと。

http://okwave.jp/qa2645307.html
    • good
    • 0
この回答へのお礼

リンク先を拝見しました。
参考にしてみます。

お礼日時:2007/01/22 18:49

単純にカウンタいれればいいのでは。


open(FILE,"test.txt") || die "Open Error.\n";
@data = <FILE>;
close(FILE);

my $count;
$count=0;
foreach (@data) {
last if($count==3);
$count++;
print $_;
}
    • good
    • 0
この回答へのお礼

foreach文の中にカウンタを入れて、
カウンタが3になれば、foreach文を抜ける方法ですね。
ありがとうございます。

お礼日時:2007/01/22 18:48

このQ&Aに関連する人気のQ&A

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

このQ&Aを見た人はこんなQ&Aも見ています

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

QPerlで特定行から特定行までを抜き出したい

皆さんのお知恵をお貸し頂ければ幸いです。

Perlで以下のようなことをしたいと考えています。
例えば、次のようなテキストファイルがあったとします。

example.log
==================================
aaaa
hogehoge
test
okok
perl
script
==================================

上記ファイルを読み込んで、「hogehoge」から「perl」の間に挟まれた行だけ抜き出したいのです。
イメージとしては、読み込んだファイルを配列に入れて、一行づつ読ませ、キーワード「hogehoge」が現れたらそこでフラグを立て、それ以降の行を表示し、キーワード「perl」が現れた時点で表示を止めるという処理になるのかな?と思っています。

このような場合、どういう風にすればいいのでしょうか?
恐れ入りますが、ご教授頂ければ幸いです。

それでは、どうぞよろしくお願い致します。

Aベストアンサー

> 一行づつ読ませ、キーワード「hogehoge」が現れたらそこでフラグを立て、それ以降の行を表示し、キーワード「perl」が現れた時点で表示を止めるという処理になるのかな?と思っています。

それでいいと思いますよ?これをそのままコード化すると、こんな感じでしょうか。(No.1さんのとはちょっと結果が違います。)

open FH, "example.log" or die $!;
$flag = 0;
while ($data = <FH>) {
  chomp $data;
  if  ($data eq "hogehoge") { $flag = 1 }
  elsif ($data eq "perl")    { $flag = 0 }
  elsif ($flag) { print "$data\n" }
}
close FH;

で、もっと略したいPerlな人だとこんな感じ。Perl独特の記法がふんだんに使われているので、勉強するには不向きかもしれませんが^^;

open FH, "example.log" or die $!;
while (<FH>) {
  print if /^hogehoge$/ .. /^perl$/ and !/^(?:hogehoge|perl)$/;
}
close FH;

※インデントに全角空白を使っているので、コピーする場合はタブなどに置換して下さい。

> 一行づつ読ませ、キーワード「hogehoge」が現れたらそこでフラグを立て、それ以降の行を表示し、キーワード「perl」が現れた時点で表示を止めるという処理になるのかな?と思っています。

それでいいと思いますよ?これをそのままコード化すると、こんな感じでしょうか。(No.1さんのとはちょっと結果が違います。)

open FH, "example.log" or die $!;
$flag = 0;
while ($data = <FH>) {
  chomp $data;
  if  ($data eq "hogehoge") { $flag = 1 }
  elsif ($data eq "perl")    { $fl...続きを読む

Q複数ファイルの読み込みについて

perl初心者です。

あるディレクトリから拡張子がdataであるファイルを全て読み込みたいのですが、方法がわかりません。
cshで書くと
foreach arg (*.data)
コマンド $arg

のようになりますが、perlだと
foreach $arg (@arg){
コマンド $arg

となりますよね?
引数がリストなのでよくわかりません。
そもそもperlではできないのでしょうか?


それともう一点ですが、ファイルオープンするときに
foreachループの中で
open(FILE, "$arg");
とすることは可能ですか?
上の質問と組み合わせて全てのファイルを開いて作業を行いたいので。

説明が下手ですいません。補足しますのでよろしくお願いします。

Aベストアンサー

while(<*.data>)
{
## $_には、*.DATAなファイル名が格納されている。
open(F,"$_"); ##openする。
while(<F>)
{
##読み出された内容が$_に格納されている。
print $_; ##出力してみる。
}
}

というのが最短コーディングです。

Qファイルの行数取得

超初心者です。

いま、表計算的なスクリプトを記述しています。

あるファイルの行数を取得する関数ってあるんでしょうか?

ファイルに記述されている数値を足したり引いたりするのですが、forを使っての計算の際にファイルの行数が必要となりました。

Aベストアンサー

Perlにですね。ないはずです。
行数とはファイルに書かれた改行文字の個数ということなので
実際にファイルを全て読み込まないと行数はわかりません。
以下のように色々な方法があると思います

#### 単純な例
$a = 0;
open FD, "<file.txt" || die $!;
while (<FD>) {
$a++;
}
close FD;
print "行数:$a\n";

### 少しマニアックな方法
open FD, "<file.txt" || die $!;
@a = <FD>;
close FD;
print "行数:" . ($#a + 1) + "\n";


### 反則的方法(外部コマンド) ... UNIXの場合
print "行数:" . `wc -l file.txt` . "\n";

QPerlでファイルの列を削除する。

どのように書けばいいかわからないので教えてください。
","で区切られたcsvファイルがあるとします。(file.csv)
そのファイルは全部で5列ありますが、4列目と5列目は値が入っている場合と無い場合があります。(1~3列目は必ず値は存在します。)
このファイルの1列目と2列目を削除して、3列目から5列目だけのファイルを作成したいのですが、どうすればいいのでしょうか?

よろしくお願いします。

Aベストアンサー

$line='a,b,c,d,,f';
($first, $second, $rest) = split(/,/,$line,3);
print $rest;
みたいにすれば、3列目以降を$restにとりだせます。
3列目以降に値が入っていない列があっても大丈夫です。

Qsedなどで、特定の文字列の後の文字列を抽出したい

sedなどで、特定の文字列の後の文字列を抽出したい

シェルスクリプト内で、sedなどを使って特定の文字列の後の文字列を抽出したいのですが、どうすればいいでしょうか?

たとえば、abcXYZ123defghiのなかから、XYZの後の「123」を抜き出したいです。

echo abcXYZ123defghi | sed ...

のようにして実行させたいです。

Aベストアンサー

日本語対応sedだと日本語数字混じりでもできますね。

echo abcXYZ12357defghi | sed -e 's/^.*XYZ\([0-90-9]*\).*$/\1/' -e 'y/0123456789/0123456789/'
12357

※ 使っている日本語コードの指定は必要かも(例えば、 --ctype=EUC)

echo abcXYZ12357defghi | sed -e 's/^.*XYZ\([0-90-9]*\).*$/\1/'
12357

※ 入力フォームに書いている時はASCIIと日本語の判別がし易いけど回答見るとわかり難いですね。後ろの例での結果57とy/0123456789/の数字部分が日本語です。

Q複数のCSVファイルを一つのCSVファイルに

ディレクトリ内に複数あるCSVファイルを一つのCSVにまとめたいのですが、方法がわからないので教えて下さい。
ファイルの読み出しと追加書き込みを繰り返せば良いとは思っています。
ディレクトリ内のファイルを検索するところまでは出来ました。

Aベストアンサー

  my $path = "./data";  #csvのあるディレクトリ
  opendir(DIR, $path) || die "Error!!";
  my @dirs = grep /\.csv$/i, readdir(DIR);
  closedir(DIR);

  if(open(OUT,">./mix.csv")){
    for my $fname (sort @dirs){
      if(open(IN,"$path/$fname")){
        my @lines = <IN>;
        print OUT @lines;
        close(IN);
      }
    }
    close(OUT);
  }

#ファイルを順に読み込んで書き込んでいるだけです。テキトウに改造してみてください。
#動作確認はしてないです。
#または、perlから、OSのコピーコマンドを呼んでファイルを結合してもいいと思います。

Qgrepで検索文字列が完全一致した行だけ取り出す方法

grepの文字列検索で検索文字列が単語として、完全一致した行だけ取り出す方法はないでしょうか?

通常は
grep hoge hoge.txt

と打つと、hogeが含まれる行が出力されますが、今回は含まれる行ではなくて完全に文字列が一致した行だけ取り出したいのです。

例えばhoge.txtの中に
cc ghoge
kkl hogem
jjll hoge
という3行があったとしたら最後の行でhogeという文字が空白で区切られた行だけ取り出したいのです。

何かよい方法があれば教えてください

Aベストアンサー

-w オプションじゃだめですか?

参考URL:http://www.linux.or.jp/JM/html/GNU_grep/man1/grep.1.html

Q巨大なテキストの最終行を取得するには

perl v5.10.0 built for i386-linux-thread-multi
OS: Fedora 9 (Linux localhost.localdomain 2.6.25.11-97.fc9.i686 #1 SMP Mon Jul 21 01:31:09 EDT 2008 i686 athlon i386 GNU/Linux)

巨大なテキストファイルの最終行を効率良く取得する方法を探しています。
検索を駆使して 6 日 6 晩試行錯誤したのですが、遂に見付けられなかった為、此所で質問させて頂きます。
私が知っている方法は以下の 3 つですが、何れも環境に依存するか、或いは効率が悪い等の理由で不完全です。

----------------
#!/usr/bin/perl

my $filename = './47GiB.txt';
my $file;

# 1.
print `tail -n 1 $filename`;

# 2.
open $file, $filename;
print +(<$file>)[- 1]; # print pop @{[<$file>]};
close $file;

# 3.
open $file, $filename;
my $pos = 0;
while (<$file>) {
$pos = tell $file unless eof $file;
}
seek $file, $pos, 0;
print <$file>;
close $file;
----------------

tail コマンドの様に、瞬時に最終行を読み出す方法は無いのでしょうか ?
御回答宜しくお願いします。

perl v5.10.0 built for i386-linux-thread-multi
OS: Fedora 9 (Linux localhost.localdomain 2.6.25.11-97.fc9.i686 #1 SMP Mon Jul 21 01:31:09 EDT 2008 i686 athlon i386 GNU/Linux)

巨大なテキストファイルの最終行を効率良く取得する方法を探しています。
検索を駆使して 6 日 6 晩試行錯誤したのですが、遂に見付けられなかった為、此所で質問させて頂きます。
私が知っている方法は以下の 3 つですが、何れも環境に依存するか、或いは効率が悪い等の理由で不完全です。

----------------
#!/us...続きを読む

Aベストアンサー

すみません, 「1回は読まないといけない」はウソです.
一度ファイルの最後までシークして, あとは
・適当な分だけ戻る
・read かなにかで読み込む
・改行があったら, そこからあとを「最後の行」とする
という感じでいけると思います. これだと実行時間はファイル全体の大きさに関係なく, 最後の行の長さにのみ依存するはずです. 最後の行に改行があるかないかまで考えるとちょっと嫌ですが.

Qperlでファイル内の文字列を置換して新たなファイルに出力

3つのファイル(list1,list2,list3)を順番に読み込んで
ファイルの中のGoodという文字をBadにして
新たにlist1_new、list2_new、list_3new
という名前のファイルに書き込みたいのですが
やり方がわかりません。 下記のプログラムを
ベースに教えていただけませんか?


#! /usr/local/bin/perl

foreach LIST ( \
list1 \
list2 \
list3 \
)

open(FILE , "${LIST}" ) || die Damedame;
while (<FILE>) {
s/Good/Bad/g ;
print;
}

Aベストアンサー

foreach $LIST ( # $付ける
list1, # カンマ
list2,
list3
)
{ # foreachカッコ
open(FILE2 , ">${LIST}_new" ) or die Damedame2; # 出力用ファイルオープン
open(FILE , "${LIST}" ) or die Damedame;
while (<FILE>) {
s/Good/Bad/g ;
print FILE2 $_; # 出力処理
}
close(FILE); # クローズ
close(FILE2); # クローズ
} # foreachカッコ

Qforeachで次の行の値を取得して処理したい

CSVテキストでforeachによる次の行の値を取得し、計算し表示したいのですがわかりません。
どなたか処理の仕方をアドバイスを下さい。

・csvの内容
2012,20,山田,奈良(1行目)
2012,15,川上,東京(2行目)
2013,10,山本,北海道(3行目)

・処理
$lines = @file($logfile);
foreach ($lines as $value){
list($value01,$value02,$value03,$value04)= explode(",", trim($value));
echo "表示: $value01 $value02 $value03 $value04";

  *ここで処理:この行の$value02と次の行の$value02を比較計算した値を表示

}

Aベストアンサー

foreachでやるなら、「現在の行を処理して次の行と比較」ではなく「前の行を処理して現在の行と比較」にすればいいんじゃないですかね。

$lines = @file($logfile);
$prev = '';
foreach ($lines as $value){
if ($prev !== '') {
list($value01,$value02,$value03,$value04)= explode(",", trim($prev));
echo "表示: $value01 $value02 $value03 $value04";
list($value01w,$value02w,$value03w,$value04w)= explode(",", trim($value));
// $value02 と $value02w を比較計算
}
$prev = $value;
}
if ($prev !== '') {
list($value01,$value02,$value03,$value04)= explode(",", trim($prev));
echo "表示: $value01 $value02 $value03 $value04";
}


fileで読んでいますから(数字添え字だし要素数も既知なので)foreachでなくforで回してもいいかもしれません。そうすれば(最大添え字を超えない範囲で)添え字+1を参照すればいいかと。

foreachでやるなら、「現在の行を処理して次の行と比較」ではなく「前の行を処理して現在の行と比較」にすればいいんじゃないですかね。

$lines = @file($logfile);
$prev = '';
foreach ($lines as $value){
if ($prev !== '') {
list($value01,$value02,$value03,$value04)= explode(",", trim($prev));
echo "表示: $value01 $value02 $value03 $value04";
list($value01w,$value02w,$value03w,$value04w)= explode(",", trim($value));
// $value02 と $value02w...続きを読む


このQ&Aを見た人がよく見るQ&A

人気Q&Aランキング