18

-fファイルをテストして、それが通常のファイルであるかどうかを確認し、それ以外のものではないと考えていました。しかし、Perl の動作は異なるようです。perldocエントリを調べたところ、次のように書かれています。

-f  File is a plain file.

次のように、 という 1 つのファイルと、それぞれが を指すfile15 つのシンボリック リンクを持つディレクトリがあるとします。1 2 3 4 5file1

-rw-r--r-- file1
lrwxrwxrwx 1 -> file1
lrwxrwxrwx 2 -> file1
lrwxrwxrwx 3 -> file1
lrwxrwxrwx 4 -> file1
lrwxrwxrwx 5 -> file1
drwxr-xr-x ../
drwxr-xr-x ./

-type fフィルターを使用してこのディレクトリで検索を実行すると、期待どおりの出力が得られます。

%  find . -type f
./file1

しかし、-f 演算子を使用して perl スクリプトを実行すると、次の出力が得られます。

%  ls | perl -e 'while(<>) { chomp; print "$_\n" if -f $_ }'
1
2
3
4
5
file1

-lあまりにもテストを追加すると、期待どおりに動作します:

%  ls | perl -e 'while(<>) { chomp; print "$_\n" if -f $_ and not -l $_}'
file1

シンボリック リンクもプレーン ファイルと見なされますか? もしそうなら、なぜですか?私のファイルテストの使い方は間違っていますか?

4

3 に答える 3

17

シンボリックリンクをテストすると、シンボリックリンクテストを使用しない限り、シンボリックリンクが指すものに対してテストが実行されます-l

これは、同様に動作するstatおよびLinux システム コールと同等です。lstatつまりstat、シンボリック リンクの場合は、シンボリック リンクのターゲットの結果が得られますが、lstatシンボリック リンクの場合は、シンボリック リンク自体の結果が得られます。この動作は意図的なものであるため、単純なプログラムはシンボリック リンクを気にする必要がなく、シンボリック リンクは意図したとおりに機能します。

-fシンボリックリンクがディレクトリを参照している場合、テストは偽であり、-dテストは真であることがわかります。

于 2012-04-25T09:25:49.407 に答える
4

クイックソリューション

$ ls | perl -lne 'print if stat && -f _'
1
2
3
4
5
ファイル1

$ ls | perl -lne 'print if lstat && -f _'
ファイル1

シンボリック リンクと検索

デフォルトでは、GNUfindはシンボリック リンクを逆参照したりたどったりしませんが、findドキュメントにはこのポリシーを変更するスイッチが記載されています。

リンクに関する find の動作を制御するオプションは次のとおりです。

-P
findシンボリック リンクを逆参照しません。これはデフォルトの動作です。このオプションは、コマンド ラインでファイル名の前に指定する必要があります。

-H
findシンボリック リンクを逆参照しません (逆参照されるコマンド ラインのファイル名の場合を除きます)。シンボリック リンクを逆参照できない場合は、シンボリック リンク自体の情報が使用されます。このオプションは、コマンド ラインでファイル名の前に指定する必要があります。

-L
find可能な場合はシンボリック リンクを逆参照し、それが不可能な場合は、シンボリック リンク自体のプロパティを使用します。このオプションは、コマンド ラインでファイル名の前に指定する必要があります。このオプションを使用すると、オプションと同じ動作も意味し-noleafます。後で-Hまたは-Pオプションを使用しても、 はオフになりません-noleaf

-follow
このオプションは「式」の一部を形成し、ファイル名の後に指定する必要がありますが、それ以外は と同等-Lです。この-followオプションは、コマンド ラインでその後に表示されるテストのみに影響します。このオプションは非推奨です。可能であれば、-L代わりに使用する必要があります。

検索コマンドを Perl に変換する

標準ディストリビューションには、古い Unix システムfind2perlと互換性のあるユーティリティが付属しています。find

$ find2perl . -タイプ f | パール
./file1

代わりに、プレーン ファイル自体またはプレーン ファイルへのリンクのいずれかであるファイルを求めることができます。

$ find2perl . -フォロー -タイプ f | パール
./1
./2
./3
./4
./5
./file1

コード生成では、File::Find モジュールから渡されるfind2perlデフォルトのサブルーチンは次のとおりです。wantedfind

sub wanted {
    my ($dev,$ino,$mode,$nlink,$uid,$gid);

    (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) &&
    -f _
    && print("$name\n");
}

しかし、で-follow、私たちは得る

sub wanted {
    my ($dev,$ino,$mode,$nlink,$uid,$gid);

    (($dev,$ino,$mode,$nlink,$uid,$gid) = stat($_)) &&
    -f _
    && print("$name\n");
}

唯一の違いは、wanted呼び出しstatかかであることに注意してくださいlstat。後者は次のように文書化されています。

lstat EXPR
lstat

関数と同じことstat(特別な_ファイルハンドルの設定を含む) を行いますが、シンボリック リンクが指すファイルの代わりにシンボリック リンクを統計します。システムにシンボリック リンクが実装されていない場合は、正常statに実行されます。詳細については、 のドキュメントを参照してくださいstat

EXPRを省略すると、stats $_.

からのサンプル出力が示すように、 filetestfind2perl演算子を使用して意図を表現できますが、 vs を選択してシンボリックリンクのセマンティクスについて正確にすることができます。statlstat

その面白い_トークン

上記_の簡単な解決策の最後にあるのは、lstatドキュメントに記載されている特別なファイルハンドルです。これらの高価なシステムコールを繰り返し行う必要がないようにするため、statまたはその方法として、最新の結果のコピーを保持します。、、、などのファイルテスト演算子も、このバッファーを埋めます。lstat-f-r-e-l

いずれかのファイル テスト (またはstatorlstat演算子) に、1 つの下線で構成される特別なファイル ハンドルが指定されている場合、前のファイル テスト (またはstat演算子) の stat 構造が使用され、システム コールが節約されます。(これは では機能しません-t。そのことを覚えておいて、実際のファイルではなく、シンボリック リンクの stat 構造体に値lstatを残す必要があります。) (また、stat バッファが呼び出しによっていっぱいになった場合は、の結果)。例:-llstat-T-Bstat _

print "Can do.\n" if -r $a || -w _ || -x _;

stat($filename);
print "Readable\n" if -r _;
print "Writable\n" if -w _;
print "Executable\n" if -x _;
于 2012-04-25T15:19:47.077 に答える
3

デフォルトでは、すべてのファイル テスト オペレータ ( を除く-l) がテストに使用stat()されます。つまり、それらはシンボリック リンクに対して透過的です。-f通常のファイル、または通常のファイルへのシンボリックリンクで true を返します。

lstat()代わりに使用するには、最初lstatに特別なファイルハンドルでファイルテストを使用する必要があります_。これには、最新のstatまたはlstat操作の結果が格納されます。

perl -e 'while(<>) { chomp; print "$_\n" if lstat $_ && -f _ }'
于 2012-04-25T16:12:49.467 に答える