- ベストアンサー
行を指定して削除する方法PERL
ある文字を検索して、その行を含む&1行前と2行後ろの行までを削除するスクリプトを書きたいのですが、上手くいきません。 検索して行番号を獲得して、 $rowという変数に入れました。 それをさらに $a :1行前 $b :2行後ろの行番号に格納しました。 問題は削除するところが上手く行きません。 next if で $aから$bの行番号を削除して、と頼んでいるのですが、空のファイルに上書きされてしまいます。 お願いです。この方法で何が間違っているかを教えてください! #!/opt/perl/5.8.0/bin/perl -w print "Content-type: text/html\n\n"; use CGI qw(:standard); use CGI::Carp qw/fatalsToBrowser/; $filename = "../XML/link.xml"; $new = "../XML/link.xsl"; open(FILE, $filename) or die "Can't open `$filename': $!"; while (<FILE>) { if($_ =~ /HRWeb/){ #print "$."; $row = $.; $a = $row-1; $b = $row+2; print "HRWeb delete rows $a through "; } } &delete ($a, $b); sub delete{ open( OLD, "< $filename" ); open( NEW, "> $new" ); while ( <OLD> ) { next if /$a/../$b/; # copy everything but $a through $b print NEW $_; }print "$a deleted $b"; close( OLD ); close( NEW ); rename( $filename, "$filename.orig" ); rename($new, $filename ); }
- みんなの回答 (6)
- 専門家の回答
質問者が選んだベストアンサー
>next if /$a/../$b/; >これですね。こんな書き方はできません。 そうですね。 next if $.==$a..$.==$b; とは書けます
その他の回答 (5)
- ___noboru___
- ベストアンサー率28% (33/117)
これは少し関係ないことですが… > &delete ($a, $b); こう書いていて sub delete の方で @_ を受け取らずにそのまま $a, $b を使うのは書き方が変です。(動かないわけではありませんが…)。 あと FILE の close() がありません。Perl なのでなくてもいいんですが、 close() されないままだとプログラムが終了するまでファイルディスクリプタを一つ使いっぱなしになると思うので、使い終わったらなるべく close() しておくのがおすすめです。 で、 delete の中ですが > next if /$a/../$b/; こうじゃなくてもっと普通に書けばいいのでは? たとえばこう書くとか。 next if ($. >= $a && $. <= $b);
- BLUEPIXY
- ベストアンサー率50% (3003/5914)
>next if $a..$b; >だと ($a, $b がどちらも数値ならば) 「$. が $a と $b の間 next を実行する」という意味. 間違い 「$. が A と B の間 next を実行する」という意味. になるのは、整数"定数"の時
- Tacosan
- ベストアンサー率23% (3656/15482)
next if /$a/../$b/; じゃなくって next if $a..$b; なら動くかも. 蛇足: スカラーコンテキストにおける範囲演算子 .. の振舞い. a .. b において 1) .. の前後がどちらも数値の場合は a <= $. && $. <= b の意味 2) そうでないときは「論理式 a が成り立ってから論理式 b が成り立つまで」の意味 next if /$a/../$b/; という書き方は可能で「$a (に入っている正規表現) にマッチしてから $b (に入っている正規表現) にマッチするまで next を実行する」という意味. next if $a..$b; だと ($a, $b がどちらも数値ならば) 「$. が $a と $b の間 next を実行する」という意味.
お礼
はい、一番最初にこれを試していたのですが、やはり駄目でした。 ですが、わざわざ書き込みありがとうございました。 感謝です。
- Ethersky
- ベストアンサー率71% (168/235)
とりあえず質問内容を元に自分で組んでみました。 $char = 'abc'; #対象文字列 $file = './file'; #ファイル open(OUT, "> $file.tmp"); open(IN, "< $file"); $skip = 0; $tmp = ''; while(<IN>){ if($skip){ $skip++; if($skip == 4){$skip = 0;} }else{ if(/$char/g){$skip = 1;} if($skip == 0){print OUT $tmp;} } $tmp = $_; } if($skip == 0){print OUT $tmp;} close(IN); close(OUT); rename("$file.tmp","$file"); > お願いです。この方法で何が間違っているかを教えてください! next if /$a/../$b/; これですね。こんな書き方はできません。 書くなら unless($. <= $b && $. >= $a){print NEW;} とか。(ちなみに$_は省略できます。)
お礼
どうもありがとうございます!! このスクリプトでも上手く行きました。 ただ、私のような初心者ではどれが何言っているのか分からなくて、プロダクションで使うのにはリスキーだと思ったので、今回は辞めましたが、非常に参考になりました。 ありがとうございます。
- BLUEPIXY
- ベストアンサー率50% (3003/5914)
基本的には、コレで良いと思いますが、 FILE がclose されずに、&delete でrename しようとしているので、 rename は、両方失敗してしまうと思います。 あと、カレントディレクトリが思う所になっているか、確認するといいと思います。
お礼
ありがとうございます! スクリプトに変数の指定意外変更する必要なく成功させることができました。 many many thanks です! ですが、午前中ずっと葛藤を続けていて、コマンドラインでは上手く行くのに、ウェブサーバーからだと実行されなくて、午後にようやく、フォルダーの権限がwriteになっていないことが判明しました・・・ おっとっと。