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

Hi I'm new to Perl and just learning. I have created the following script as a test to see how the symlink function works. there are a total of five files within a directory. im attempting to symbolicly link these files to the parent directory giving the link the same name as the file. However one of the files is an executable binary and the script will not create the link. Does anyone know where I'm going wrong.
#!/usr/bin/perl -w my $dir = "/home/test/folder"; opendir(BIN, $dir) || die "Can't open $dir: $!"; my @array = grep { -T "$dir/$_" } readdir BIN; foreach $file (@array) { $file = symlink ("/home/test/folder/$file","/home/folder/$file") }

Replies are listed 'Best First'.
Re: symbolic links
by Joost (Canon) on Jun 25, 2007 at 21:30 UTC
    my @array = grep { -T "$dir/$_" } readdir BIN;

    your  grep { -T "$dir/$_" } selects everything that appears to be a text file. If your executable is a compiled program (i.e. not an executable script) it's probably getting filtered out.

    If you want to link to every file, you can use grep { -f "$dir/$_" }.

    See also -X and grep.

    As an aside, I strongly recommend you use strict at the top of every script. It'll catch a lot of errors at compile time that might otherwise become hard to locate bugs. For your script to work with strict, you need to declare $file, like so:

    # ... foreach my $file (@array) { # ...

      As Joost++ points out, the problem in your code is that it checks only for text files (-T), hence not including your executable binary.

      Also, if you're trying to create the link on the parent directory, the destination string should read "/home/test/", not "/home/folder" (you should probably not hardcode it like that either, as any typo can bring unexpected bugs like this one. Use you $dir variable! :-)

      But what I would really warn you about is on putting the returned value of symlink() back on $file. Not only it destroys your filename for further use, the variable name differing from what it actually does (or any multi-use variable at any rate) will most likely confuse you if your program escalates.

      Even worse, if a user tries to run your program on a filesystem that does not support symbolic links, it will cause a fatal error unless you trap it in an eval block. You could do something like:

      #!/usr/bin/perl use strict; use warnings; my $dir = "/home/test/folder"; opendir(BIN, $dir) or die "Can't open $dir: $!\n"; my @array = grep { -f "$dir/$_" } readdir BIN; foreach my $file (@array) { eval { symlink ("$dir/$file","$dir/../$file") }; # links to parent if ($@) { print "could not create symlink for $file\n"; } else { print "success!\n"; } }
      Of course, if this is just a simple PoC code where you were not particularly concerned with the pointed issues, feel free to ignore them :-)

      Hope this helps!

        Hi Hope you don’t mind but I have another question. I have been playing around with the script the only thing I’m having trouble with now is that I have tried to create a symbolic link to an ordinary file as well as a binary but can seem to link to a folder. Any thoughts or suggestions would be greatly received. Thanks for all your help.