Как я могу извлечь только элементы, которые я хочу из массива Perl? - PullRequest
3 голосов
/ 19 мая 2010

Эй, мне интересно, как я могу заставить этот код работать. В основном я хочу сохранить строки $filename, пока они содержат $user в пути:

        open STDERR, ">/dev/null";
        $filename=`find -H /home | grep $file`;
        @filenames = split(/\n/, $filename);
        for $i (@filenames) {
            if ($i =~ m/$user/) {
                #keep results
            } else {
                delete  $i; # does not work.    
            }
        }
        $filename = join ("\n", @filenames);
        close STDERR;

Я знаю, что вы можете удалить как delete $array[index], но у меня нет индекса с таким циклом, о котором я знаю.

Ответы [ 4 ]

10 голосов
/ 19 мая 2010

Вы можете заменить свой цикл на:

@filenames = grep /$user/, @filenames;
3 голосов
/ 19 мая 2010

Нет способа сделать это, когда вы используете foreach цикл. Но не бери в голову. Правильнее всего использовать File :: Find для выполнения вашей задачи.

use File::Find 'find';

...

my @files;
my $wanted = sub {
    return unless /\Q$file/ && /\Q$user/;
    push @files, $_;
};

find({ wanted => $wanted, no_chdir => 1 }, '/home');

Не забудьте экранировать переменные с помощью \Q для использования в регулярных выражениях.

Кстати, перенаправление вашего STDERR на /dev/null лучше записать как

{
    local *STDERR;
    open STDERR, '>', '/dev/null';
    ...
}

Восстанавливает дескриптор файла после выхода из блока.

2 голосов
/ 20 мая 2010

Если вы хотите удалить элемент из массива, используйте мультивалютную функцию splice.

my @foo = qw( a b c d e f );

splice( @foo, 3, 1 ); # Remove element at index 3.

С помощью splice вы можете выполнять любые другие манипуляции. См. perldoc для получения дополнительной информации.


Как намекает на кодхолик, вы никогда не должны модифицировать массив, повторяя его с помощью цикла for. Если вы хотите изменить массив во время итерации, используйте цикл while.

Причина этого в том, что for оценивает выражение в скобках один раз и сопоставляет каждый элемент в списке результатов с псевдонимом. Если массив изменится, указатели испортятся, и последует хаос.

A while оценивает условие каждый раз в цикле, поэтому вы не столкнетесь с проблемами с указателями на несуществующие значения.

2 голосов
/ 20 мая 2010

Если у вас есть find, который поддерживает -path, то сделайте это за вас, например, ,

#! /usr/bin/perl

use warnings;
use strict;

my $user = "gbacon";
my $file = "bash";

my $path = join " -a " => map "-path '*$_*'", $user, $file;
chomp(my @filenames = `find -H /home $path 2>/dev/null`);

print map "$_\n", @filenames;

Обратите внимание, что обратные пометки в контексте списка возвращают список строк (включая их терминаторы, удаленные выше с помощью chomp) из выходных данных команды. Это избавит вас от необходимости split самостоятельно.

Выход:

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