brianMonk has asked for the wisdom of the Perl Monks concerning the following question:

Hello, I have the following issue (i.e, i am not sure how to implement the thing that I need). I have a file "test.txt" containing the following two lnes:
vc66, 17 Almond Close Whitstable Kent, vc66@canterbury.ac.uk, 0128, ac +398, 18/09/2010, 09/03/2012 lb348, 42 Alicia Avenue Dover Kent, lb348@canterbury.ac.uk, 0723, ac39 +8, 02/02/2007, 01/03/2010
What i have to do is the following: The program will ask the user for the username that they want to delete. Username is first item in each row (vc66, lb348). Next, the system will delete the whole row depending on the username that the user enters. For example, if I enter lb348, the program should delete second row and leave only first row in the file. What I was thinking to do here: Send every line to an array. My array will contain two lines. Next, I assume I could use grep function for deleting row. But I am confused about how to implement all this.

Replies are listed 'Best First'.
Re: problem with deleting a row
by Corion (Patriarch) on Nov 21, 2013 at 11:58 UTC

    Provided that your data is "not too large", Tie::File allows you to treat a file like an array.

    Removing a line would then be mostly a judicious application of splice to that array.

Re: problem with deleting a row
by Ea (Chaplain) on Nov 21, 2013 at 12:33 UTC
    My reply is from the Perl Cookbook Modifying a File in Place with -i switch and it takes place all on the command line.

    perl -i.orig -ne 'print unless /^lb348,/' test.txt
    The original file is copied to test.txt.orig and the new file has all lines that do not begin (that's what the ^ anchor is for) with lb348 followed by a comma. (The -n says to loop over all the lines in the filenames given in the argument list, so this works on many files at once. The -e says to execute the bit of code between the quotes.)

    If you're sysadmining, slinging files around as quick as you can, learning to use the command line will save you time.

    Sometimes I can think of 6 impossible LDAP attributes before breakfast.
      Ea, thanks very much for your code, it works. However, I have to make a script, not command line statement. And I done this:
      #!/usr/bin/perl -w open( FILE, "<", "test.txt") or die "cannot open > test.txt: $!"; while (<FILE>) { @array = <FILE>; @a = grep (/^lb348,/, @array); close FILE; print $a; }
      But it does not work. Sorry, I am new to programming.

        This:

        while (<FILE>) { @array = <FILE>;
        is just wrong. Either you read the file line by line with a while loop, or you "slurp" it into an array, but don't do both. The you are constructing a @a array and print $a, a scalar variable. The following pragmas:
        use strict; use warnings;
        would have picked up these errors.

        I've been writing Perl for 17 years and I'm still learning new and better ways to write code. Here's another way based on kcott's excellent answer below.
        #!/usr/bin/perl -w use strict; use autodie; my ($user_file, $changed_file) = qw{test.txt test.txt.mod}; open my $in_fh, '<', $user_file; open my $out_fh, '>', $changed_file; print "Which user? "; my $user = <STDIN>; chomp $user; print $out_fh grep !/^$user,/, <$in_fh>;
        This one slurps the whole file with the angle brackets, passes it through grep to filter the output which gets printed to the output file. Note the exclamation mark in front of the regex. It's the "not" operator which says you don't want the matching lines in your output.

        Keep working at it. From the long list of replies, you've certainly piqued the Monks' interest.

        Sometimes I can think of 6 impossible LDAP attributes before breakfast.
        Well I managed to do this. The code returns every line except the one that the user wants to delete entering first username. However, if in my test.txt file two usernames start with the same letter (for example, la123 and lv444), the program will remove both lines, regardless user input that is for example la123.
        $file = "test.txt"; print "Enter the username you want to remove from the information.txt +file\n"; $user = <STDIN>; open( FILE, $file) or die "cannot open > test.txt: $!"; while (<FILE>) { chomp; @array = <FILE>; @a = grep (!/^[$user]/, @array); print @a; }
Re: problem with deleting a row
by kcott (Archbishop) on Nov 22, 2013 at 04:36 UTC

    G'day brianMonk,

    Welcome to the monastery.

    Here's another way to do it. While this is a working script, it's really just skeleton code. You may want to add feedback about whether the supplied username was found as well as a confirmation of the deletion.

    #!/usr/bin/env perl use strict; use warnings; use autodie; my ($user_file, $changed_file) = qw{test.txt test.txt.mod}; open my $in_fh, '<', $user_file; open my $out_fh, '>', $changed_file; print 'Enter user to delete: '; chomp(my $user = <>); while (<$in_fh>) { print $out_fh $_ unless /^\Q$user\E,/; } close $in_fh; close $out_fh; rename $changed_file, $user_file;

    -- Ken

Re: problem with deleting a row
by trippledubs (Deacon) on Nov 21, 2013 at 16:42 UTC
    #!/usr/bin/env perl use strict; use warnings; use Text::CSV; use Data::Dumper; my $file="test.txt"; my $csv = Text::CSV->new({binary => 1,allow_whitespace => 1}); open my $fh, "<:encoding(utf8)", $file or die "Could not open $file: $ +!\n"; my @rows; while (my $row = $csv->getline($fh)) { push @rows,$row; } my $user_to_delete = shift; if ($user_to_delete) { @rows = grep { $_->[0] !~ /$user_to_delete/ } @rows; print Dumper @rows; } else { die "No user entered\n"; }

    Hi BrianMonk,

    If you will be parsing CSV files, using Text::CSV is a good idea. It handles fields where there may be a comma in the data and other good things I'm sure.

Re: problem with deleting a row
by taint (Chaplain) on Nov 21, 2013 at 15:38 UTC
    Greetings, brianMonk.

    Would chomp help you here? It will happily consume/read your file on a line-by-line basis, thereby allowing you to run a RE (regex) comprised of your users input against your file.

    That's probably how I'd approach it, anyway. :)

    HTH, and best wishes.

    --Chris

    #!/usr/bin/perl -Tw
    use Perl::Always or die;
    my $perl_version = (5.12.5);
    print $perl_version;