Почему оператор проверки файлов Perl "-l" не обнаруживает символические ссылки?
Почему оператор тестирования файла 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") ...
в сценарии снова "символическая ссылка" не указана, а "обычный_файл" указан дважды, но они перечислены внутри блока, предназначенного для перехвата символических ссылок, то есть:
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 ответа
perldoc Cwd
:
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
на следующем этапе?
Обратите внимание, что в приведенном выше выводе символическая ссылка (названная "symlink") не указана, а файл "обычный_файл" указан дважды.
Да, потому что ты использовал abs_path
превратить symlink
в /temp2/test/regular_file
, Избавьтесь от этой линии.
Кстати, вам не хватает
$file = "$targetDir/$file";
Единственная причина, по которой ваша программа работала без нее, заключается в том, что $targetDir
случилось, что текущий рабочий каталог.