Очистка имени каталога (удаление «..» и «.» Из имени каталога) - PullRequest
3 голосов
/ 17 ноября 2010

Я пишу модуль SFTP, используя класс Java (Да. Я знаю, что это глупо. Да, я знаю о Net :: SFTP. Политически, почему мы должны делать это так).

Базовая Java-программа имеет в основном несколько классов для получения, размещения, перечисления и удаления файла с сервера.В этих вызовах вы должны указать каталог и файл.Нет способа выйти за пределы вашего исходного каталога.Вы застряли, отслеживая сами.

Я решил, что было бы неплохо, если бы я отслеживал ваш удаленный каталог и создал метод Chdir, который отслеживает каталог, в котором вы находитесь, из корня FTP.Все, что я делаю - это сохраняю каталог внутри атрибута и использую его в других командах.Очень просто и работает.

Проблема в том, что имя хранимого каталога становится все длиннее и длиннее.Например, если каталог foo/bar/barfoo, а вы делаете $ftp->Chdir("../.."), ваш новый каталог будет foo/bar/barfoo/../.., а не foo.И то, и другое технически правильно, но первое чище и проще для понимания.

Мне нужен код, который позволит мне упростить имя каталога.Я думал об использовании File::Spec::canonpath, но это конкретно говорит о том, что не делает это.Он ссылался на Cwd, но это зависит от прямого доступа к машине, и я подключаюсь по FTP.

Я придумала следующий фрагмент кода, но ему действительно не хватает элегантности.Это должно быть проще и понятнее:

use strict;
use warnings;

my $directory = "../foo/./bar/./bar/../foo/barbar/foo/barfoo/../../fubar/barfoo/..";

print "Directory = $directory\n";
$directory =~ s{(^|[^.])\.\/}{$1}g;
print "Directory = $directory\n";
while ($directory =~ s{[^/]+/\.\.(/|$)}{}) {
    print "Directory = $directory\n";
}
$directory =~ s{/$}{};
print "Directory = $directory\n";

Есть идеи?Я хотел бы избежать установки модулей CPAN.Их может быть чрезвычайно сложно установить на нашем сервере.

Ответы [ 4 ]

6 голосов
/ 17 ноября 2010

Если бы я писал это, я бы разбил строку каталога на / и прошел бы по каждой части.Поддерживая стек частей, запись .. означает «pop», . означает «ничего не делать», а все остальное означает «вытолкнуть» эту строку в стек.Когда вы закончите, просто присоединитесь к стеку с / в качестве разделителя.

my @parts = ();
foreach my $part (File::Spec->splitdir($directory)) {
    if ($part eq '..') {
        # Note that if there are no directory parts, this will effectively
        # swallow any excess ".." components.
        pop(@parts);
    } elsif ($part ne '.') {
        push(@parts, $part);
    }
}

my $simplifiedDirectory = (@parts == 0) ? '.' : File::Spec->catdir(@parts);

Если вы хотите сохранить ведущие записи .., вам придется сделать что-то вроде этого:

my @parts = ();
my @leadingdots = ();

foreach my $part (File::Spec->splitdir($directory)) {
    if ($part eq '..') {
        if (@parts == 0) {
            push(@leadingdots, '..');
        } else {
            pop(@parts);
        }
    } elsif ($part ne '.') {
        push(@parts, $part);
    }
}

my $simplifiedDirectory = File::Spec->catdir((@leadingdots, @parts));
2 голосов
/ 18 ноября 2010

У меня есть чистый Perl-модуль на CPAN для обрезки путей: Path :: Trim . Скачайте, скопируйте и используйте его из своего рабочего каталога. Должно быть легко.

1 голос
/ 17 ноября 2010

Я не уверен, что вы можете получить доступ к этому каталогу.

Если вы можете, вы можете перейти в этот каталог и сделать getcwd там:

my $temp = getcwd;          # save the current directory
system ("cd $directory");   # change to $directory
$directory = getcwd;        
system ("cd $temp");        # switch back to the original directory
0 голосов
/ 18 ноября 2010

Протокол SFTP поддерживает команду realpath, которая делает то, что вы хотите.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...