Почему оператор проверки файлов Perl "-l" не обнаруживает символические ссылки? - PullRequest
0 голосов
/ 06 мая 2018

Почему оператор проверки файлов Perl "-l" не может обнаружить символические ссылки при следующих условиях?

Информация о системе

john@testbed-LT:/temp2/test$ uname -a
Linux Apophis-LT 4.13.0-37-generic #42-Ubuntu SMP Wed Mar 7 14:13:23 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

john@testbed-LT:/temp2/test$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 17.10
Release:        17.10
Codename:       artful

Perl Info

john@testbed-LT:/temp2/test$ perl -v

This is perl 5, version 26, subversion 0 (v5.26.0) built for x86_64-linux-gnu-thread-multi (with 56 registered patches, see perl -V for more detail)

Тестовые ресурсы

john@testbed-LT:/temp2/test$ touch regular_file
john@testbed-LT:/temp2/test$ mkdir dir
john@testbed-LT:/temp2/test$ ln -s regular_file symlink

john@testbed-LT:/temp2/test$ ls -al
total 12
drwxrwxr-x 3 john john 4096 May  6 02:29 .
drwxrwxrwx 6 john john 4096 May  6 02:29 ..
drwxrwxr-x 2 john john 4096 May  6 02:29 dir
-rw-rw-r-- 1 john john    0 May  6 02:29 regular_file
lrwxrwxrwx 1 john john   12 May  6 02:29 symlink -> regular_file

Скрипт, содержащий ошибочный оператор "-l"

john@testbed-LT:/temp2/test$ cat ~/.scripts/test.pl
#!/usr/bin/perl

use strict;
use warnings;
use Cwd 'abs_path';

my $targetDir = "/temp2/test";
opendir(DIR, $targetDir) || die "Can't open $targetDir: $!";

while (readdir DIR) {
    my $file = "$_";

    if($file =~ m/^\.{1,2}/) {
        next;
    }

    $file = abs_path($file);

    if(-l "$file") {
        print "Link: $file\n";
    }
    elsif(-d "$file") {
        print "Dir: $file\n";
    }
    elsif(-f "$file") {
        print "File: $file\n";
    }
    else {
        print "\n\n *** Unhandled file type for file [$file]!\n\n";
        exit 1;
    }
}

closedir(DIR);

Вывод скрипта

john@testbed-LT:/temp2/test$ perl ~/.scripts/test.pl
File: /temp2/test/regular_file
Dir: /temp2/test/dir
File: /temp2/test/regular_file

Проблема, которую я пытаюсь решить

Обратите внимание, что в приведенном выше выводе символическая ссылка (называемая "symlink") не указана, в то время как файл "регулярный_файл" указан дважды (я хочу, чтобы в списке была "символическая ссылка" - действительная ссылка, а не файл, на который он указывает).

Когда я изменяю ... if(-l "$file") ... на ... if(lstat "$file") ... в сценарии, снова «symlink» не отображается, а «normal_file» указывается дважды, но они перечислены внутри блока, предназначенного для перехвата символических ссылок, , т.е.

john@testbed-LT:/temp2/test$ perl ~/.scripts/test.pl
Link: /temp2/test/regular_file
Link: /temp2/test/dir
Link: /temp2/test/regular_file

Цель

Вывод, который я пытаюсь получить (, который подделан ниже - на самом деле не генерируется скриптом, а вручную ):

john@testbed-LT:/temp2/test$ perl ~/.scripts/test.pl
File: /temp2/test/regular_file
Dir: /temp2/test/dir
Link: /temp2/test/symlink

... но не обязательно в таком порядке (мне не важен порядок листинга).

Почему вышеприведенный скрипт не достигает вышеуказанной цели (почему не работает оператор "-l")

Ответы [ 2 ]

0 голосов
/ 06 мая 2018

Обратите внимание, что в вышеприведенных выходных данных символическая ссылка (называемая "symlink") не указана, а файл "обычный_файл" указан дважды

Да, потому что вы использовали abs_path, чтобы превратить symlink в /temp2/test/regular_file. Избавьтесь от этой линии.


Кстати, вам не хватает

$file = "$targetDir/$file";

Единственная причина, по которой ваша программа работала без нее, заключается в том, что $targetDir оказался текущим рабочим каталогом.

0 голосов
/ 06 мая 2018

perldoc Cwd * * 1004

abs_path

my $abs_path = abs_path($file);

Использует тот же алгоритм, что и getcwd (). Символьные ссылки и компоненты относительного пути ("." И "..") разрешаются , чтобы возвращать каноническое имя пути, точно так же, как realpath (3). При ошибке возвращается undef с $!, установленным для указания ошибки.

(Акцент мой.)

Если вы хотите увидеть символические ссылки, не используйте abs_path.

Вместо этого вы хотите

$file = "$targetDir/$file";

т.е. добавьте имя прочитанного каталога $file из.


Дополнительные примечания:

opendir(DIR, $targetDir) || die "Can't open $targetDir: $!";

while (readdir DIR) {
    my $file = "$_";

должно быть

opendir(my $dh, $targetDir) || die "Can't open $targetDir: $!";

while (my $file = readdir $dh) {
  • Зачем использовать дескрипторы файлов без слов, когда вы можете просто использовать обычные переменные (которые имеют правильную область)?
  • Нет смысла цитировать "$_" здесь.
  • Зачем сначала присваивать $_, когда вы просто собираетесь скопировать строку в $file на следующем шаге?
...