http://qs321.pair.com?node_id=1059303

Bloodnok has asked for the wisdom of the Perl Monks concerning the following question:

G'day most revered brethren ,

My reading of the file test operators perldoc (perl v5.14.2 on 32 bit Linux) suggests that the -f test will return true iff the file being tested is a regular file. However, when recently putting this to the test, I observed unexpected behaviour when run against a sym link - the following code is a simple demo of, what I consider to be, the problemmatic behaviour ...

$ file file file: empty $ file link link: symbolic link to `file' $ $ perl -e 'printf "%d%d%d%d\n", -f "file", -f "link", -l "file", -l "l +ink"' 1101
As you see, -f returns a true value for the sym link which, IMO, is most definitely not a regular file; So the question is: is it my reading of perldoc or is it actually errant behaviour ?

I thank you in advance in anticipation of your consideration of the above.

UPDATE: As was suggested by choroba, it seems, on AIX, Solaris & Linux at least, as though symlinks are indeed followed .. and the same holds true for the -f and -d operators in the shell ... which begs the question: what on earth is the point of the -follow option to the find(1) command ?

A user level that continues to overstate my experience :-))

Replies are listed 'Best First'.
Re: Should -f test return true for symlinks ?
by choroba (Cardinal) on Oct 23, 2013 at 13:35 UTC
    Have you tried comparing the behaviour with that of test or [[ -f ... ]] in bash?
    لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
      That's a good point, very well made choroba, -f "works" in exactly the same odd way in bash.

      A user level that continues to overstate my experience :-))
Re: Should -f test return true for symlinks ? (lstat)
by tye (Sage) on Oct 23, 2013 at 15:00 UTC

    The documentation is clear, if you don't just skim parts of it. "-f $path" calls stat(). "-l $path" calls lstat(). So, "-f $path" will be true for a link to a file.

    If you want -f to be false for a symlink, then you do "-f _" preceded by something that calls lstat(); that is, either "-l $path" or "lstat $path".

    - tye        

Re: Should -f test return true for symlinks ? [RESOLVED]
by MidLifeXis (Monsignor) on Oct 23, 2013 at 17:28 UTC

    (comment on OP's followup question in the UPDATE): The point of the -follow option on find is to allow you to follow a symlink when traversing directories. The default is off*. find $DIR -follow | xargs $something_destructive would be a bad thing to have run, as it could escape from $DIR.

    * I saw an instance of this in a previous life when a root cleanup job included -follow, and there was a symlink into a networked file system. Cleaned up the entire shared file system. :-/

    --MidLifeXis

      also, with "-follow" implementation needs to track all visited directories, to avoid cyclic links, and thus use more memory.
      TFT MidLifeXis, never even considered that ... as you can tell :-)

      A user level that continues to overstate my experience :-))
Re: Should -f test return true for symlinks ?
by toolic (Bishop) on Oct 23, 2013 at 13:39 UTC
    I agree that the Perl document does not explicitly state the behavior in this case. But, you could test if it is both a file and a link:
    $ perl -e 'printf "%d%d%d%d%d\n", -f "file", -f "link", -l "file", -l +"link", -f "link" and -l "link"' 11011

    Caution: I haven't tested all the combos of files/dirs/links, etc.

      Indeed I could;-/

      I'll also raise a defect against the file test operator document to make plain the fact that the link is followed and suggest another use case when trying to determine a truly plain file.

      A user level that continues to overstate my experience :-))
Re: Should -f test return true for symlinks ?
by Utilitarian (Vicar) on Oct 23, 2013 at 13:43 UTC
    $ perl -e 'printf "File test: file %d f_link %d dir %d d_link %d\n" , +-f "file" , -f "f_link", -f "dir", -f "d_link"; ' File test: file 1 f_link 1 dir 0 d_link 0 $ perl -e 'printf "Dir test: file %d f_link %d dir %d d_link %d\n" ,- +d "file" , -d "f_link", -d "dir", -d "d_link"; ' Dir test: file 0 f_link 0 dir 1 d_link 1
    So it would appear that the symlink is followed by the test ...

    print "Good ",qw(night morning afternoon evening)[(localtime)[2]/6]," fellow monks."
Re: Should -f test return true for symlinks ?
by Anonymous Monk on Oct 23, 2013 at 14:04 UTC
    It seems to be following the link. If "bar" is a symlink to "foo," "-f" will return true for both of them. If you then remove "foo," leaving the now-orphaned symlink, it will now return false for both of them.