2

複数のファイルの文字列を置き換えようとしています。ただし、最初のファイルのみが置き換えられます。コードは次のとおりです。

perl -pi -e 's/(^<section_begin>.*\s+$)/\1<expand>\n/ if $.==1' *exp`

grep -iw "expand" *exp
a3exp:<expand>

個々のファイルに同じコマンドを使用すると、機能します。

perl -pi -e 's/(^<section_begin>.*\s+$)/\1<expand>\n/ if $.==1' n2exp
grep -iw "expand" *exp
a3exp:<expand>
n2exp:<expand>

この問題を解決するのを手伝ってもらえますか?

4

5 に答える 5

4

perlvarによると:

$. ファイルハンドルが閉じられるとリセットされますが、close() を介さずに開いているファイルハンドルが再度開かれるとリセットされません。

"<>" は明示的な終了を行わないため、ARGV ファイル全体で行番号が増加します(ただし、eof の例を参照してください)。

(2 番目の強調を追加)

を使用する-pと、@ARGVコマンドラインで渡したファイルのリストに設定されます。次のファイルに移動しても はリセットされないため$.、最初のファイルの場合は 1 になります。これは、次のように印刷するだけで確認できます$.

$ echo foo > foo
$ echo bar > bar
$ perl -pe 'print "$. "' *
1 bar
2 foo

( with-p行は自動的に印刷されるため、上記の例では、各行の内容が の値の横に印刷されます$.)

mpapec が提案するように、次のファイルに移動するときに特別closeなファイルハンドルを使用すると、期待どおりに動作します。ARGV$.

$ perl -pe 'print "$. "; close ARGV if eof' *
1 bar
1 foo

詳細といくつかの良い例については、eof のドキュメントを参照してください。

于 2013-10-16T15:39:41.240 に答える
2

eofまたはを使用eof(ARG)して、各ファイルの終わりを検出し、$.それに応じてリセットすることができます。

ドキュメントから

while (<>) ループでは、eof または eof(ARGV) を使用して各ファイルの終わりを検出できますが、eof() は最後のファイルの終わりのみを検出します。例:

# reset line numbering on each input file
while (<>) {
    next if /^\s*#/;  # skip comments
    print "$.\t$_";
} continue {
    close ARGV if eof;  # Not eof()!
}

http://perldoc.perl.org/functions/eof.html

于 2013-10-16T15:46:09.173 に答える
2

Unix シェルには、この問題を回避するための多くのツールがあります。ありfindます-exec

find . -name \*exp -exec perl -pi -e '... if $.==1' {} \;

または昔ながらのforループ。それbashは次のようになります

for file in *exp
do
    perl -pi -e '... if $.==1' file
done
于 2013-10-16T15:41:34.617 に答える
0

あなたの if $.==1 はあなたを手に入れていると思います。それは処理された行です: 入力の最初の行だけを処理するように指示しています。

于 2013-10-16T16:01:40.530 に答える