forでは$.はカウントされない

ちょっと違うので横から。

これはforの動作というより、式の評価コンテキストの問題。

forはその性質上、操作対象は配列になる:
for (<>) {
     ....
}

# 上記はこれと同等
my @lines = <>;
for(@lines) {
    ....
}
なので、<>も配列として評価されるべく*まず最初に*<>を最後まで読み切って、行区切りの配列を作ってからforに渡す。このときファイルハンドルを読み切っているので、当然 $.はファイル全体の行数になる。

これに対して、whiileは対象を毎ループ評価するので、1行ずつの読み込みになる。だから$.は行毎の値になる。B::Deparseを使うとちょっとわかるかも。
# こっちはちょっと正直わかりにくいとは思うけど・・・
daisuke@beefcake $ perl -MO=Deparse -e 'print $. . $_ for <>'
;
print $. . $_ foreach (<ARGV>);
-e syntax OK

# こちらでは $_ = という操作になっているので、1行毎読み込んでるのが
# はっきりわかる。
daisuke@beefcake $ perl -MO=Deparse -e 'print $. . $_ while <>'
print $. . $_ while defined($_ = <ARGV>);
-e syntax OK
というわけで、forが違うというよりはファイルハンドルをリストコンテキストで読み込んだ場合とスカラーコンテキストで読み込んだ場合の動作が違う、っていうのが正解。