LINUX.ORG.RU

Рекурсивный вывод содержимого каталога в форме дерева в Perl

 , ,


0

1

Привет! Помогите сильно начинающему, будьте добры. Задача - в названии темы. Т.е я задаю скрипту путь - он мне выплевывет содержимое рекурсивно в виде дерева. На данный момент имеется такое:

#!/usr/bin/perl
use strict;
use warnings;

my $start_level = 0;
my $src = $ARGV[0];

print "$ARGV[0]\n";
my @arr = sort_ ($ARGV[0], $start_level);

sub sort_ {
    my ($src, $level) = @_; 
    opendir (my $dh, $src);
    my @sort_dir = grep {!/^\.{1,2}$/} map $_->[0], sort {$a->[1] <=> $b->[1] || $a->[0]cmp $b->[0] } map [ $_, -f "$src/$_"], readdir ($dh); #здесь убираются файлы . и .. и происходит сортировка
    closedir ($dh);
    foreach my $elem (@sort_dir) {
        if ( -d "$src/$elem" ) { 
            printf "%s|- %-10s\n", '|   ' x $level, $elem;
            sort_ ("$src/$elem", ++$level); # если элемент - папка, вызываем рекурсию по новой, добавляем счетчик уровней вложености
            $level = $level -1; # и сразу убавляем, для следующих элементов
        } else {
            printf "%s|- %-10s\n", '|   ' x $level, $elem;
          }   
    }   
}
Который выводит результат следующего вида:
/boot/
|- efi       
|   |- EFI       
|   |   |- redhat    
|   |   |   |- grub.efi  
|- grub      
|   |- device.map
|   |- e2fs_stage1_5
|   |- fat_stage1_5
|   |- ffs_stage1_5
|   |- grub.conf 
|   |- iso9660_stage1_5
|   |- jfs_stage1_5
|   |- menu.lst  
|   |- minix_stage1_5
|   |- reiserfs_stage1_5
|   |- splash.xpm.gz
|   |- stage1    
|   |- stage2    
|   |- ufs2_stage1_5
|   |- vstafs_stage1_5
|   |- xfs_stage1_5
|- lost+found
|- .vmlinuz-2.6.32-431.el6.x86_64.hmac
|- System.map-2.6.32-431.el6.x86_64
|- config-2.6.32-431.el6.x86_64
|- initramfs-2.6.32-431.el6.x86_64.img
|- symvers-2.6.32-431.el6.x86_64.gz
|- vmlinuz-2.6.32-431.el6.x86_64
Вопрос: подскажите «алгоритм последнего элемента», как сделать так что бы не печатались вертикальные палки (которые привязаны к уровню вложености $level), когда это не нужно (последний элемент субдиректории)? Надо вот так:
|- efi       
|    |- EFI       
|         |- redhat    
|             |- grub.efi

Заранее спасибо!



Последнее исправление: dimdiden (всего исправлений: 1)

как сделать так что бы не печатались вертикальные палки

Проверять, есть ли у директории еще содержимое, до печати текущего элемента

Зачем эти палки? Есть же специальные знаки в unicode:

% systemd-cgls |head 
├─1 /lib/systemd/systemd
├─system.slice
│ ├─dbus.service
│ │ └─346 /usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfi...
│ ├─dhcpcd.service
│ │ └─361 /usr/bin/dhcpcd -q -b
│ ├─lxdm.service
│ │ ├─368 /usr/sbin/lxdm-binary
│ │ └─407 /usr/bin/Xorg.bin :0 vt07 -nolisten tcp -novtswitch
│ ├─xephyr-wm.service

disarmer ★★★
()
Ответ на: комментарий от disarmer

Зачем вообще что-то изобретать, когда есть кошерная комманда tree?

beastie ★★★★★
()
#!/usr/bin/perl
use strict;
use warnings;

my $start_level = 1;
my $src = $ARGV[0];

print "$ARGV[0]\n";
my @arr = sort_ ($ARGV[0], $start_level);

sub sort_ {
    my ($src, $level) = @_; 
    opendir (my $dh, $src) || return;
    my @sort_dir = grep {!/^\.{1,2}$/} map $_->[0], sort {$a->[1] <=> $b->[1] || $a->[0]cmp $b->[0] } map [ $_, -f "$src/$_"], readdir ($dh); #здесь убираются файлы . и .. и происходит сортировка
    closedir ($dh);
    for (my $i=0; $i < @sort_dir; $i++) {
	my $elem = $sort_dir[$i];
	my $last = $i eq (@sort_dir -1);
	my $head = $level eq $start_level;
	if ( -d "$src/$elem" or $head) {
		my $headSymbol = ($last and $head) ? "└" : "├";
		my $space = "──";
		printf "%s%s %s\n", $headSymbol, $space x $level, $elem;
	} else {
		my $headSymbol = "│";
		my $space = "  ";
		my $space2 = $last ? "└" : "├";
		printf "%s%s %s── %s\n", $headSymbol, $space x ($level-1), $space2, $elem;
	}
	sort_ ("$src/$elem", $level+1) if ( -d "$src/$elem" );
    }
}
vtVitus ★★★★★
()
Последнее исправление: vtVitus (всего исправлений: 2)
Ответ на: комментарий от vtVitus

Ты крут!!! Работает обалденно. Пошел копаться в коде

dimdiden
() автор топика
Ответ на: комментарий от vtVitus

Сори что напрягаю. Немного некорректно выводит все что дальше второго уровня вложенности. Вот некорректно /boot/efi/EFI/redhat. Создал папку /boot/grub/1 и она выводит тоже не так, и рвет линию к файлам в папке /boot/grub.

/boot/
├── efi
├──── EFI
├────── redhat
│       └── grub.efi
├── grub
├──── 1
│     └── 123
│   ├── device.map
│   ├── e2fs_stage1_5
│   ├── fat_stage1_5
│   ├── ffs_stage1_5
│   ├── grub.conf
│   ├── iso9660_stage1_5
│   ├── jfs_stage1_5
│   ├── menu.lst
│   ├── minix_stage1_5
│   ├── reiserfs_stage1_5
│   ├── splash.xpm.gz
│   ├── stage1
│   ├── stage2
│   ├── ufs2_stage1_5
│   ├── vstafs_stage1_5
│   └── xfs_stage1_5
├── lost+found
├── .vmlinuz-2.6.32-431.el6.x86_64.hmac
├── System.map-2.6.32-431.el6.x86_64
├── config-2.6.32-431.el6.x86_64
├── initramfs-2.6.32-431.el6.x86_64.img
├── symvers-2.6.32-431.el6.x86_64.gz
└── vmlinuz-2.6.32-431.el6.x86_64

dimdiden
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.