I'm trying a single from a large ".tgz" file. I'm using Archive::Tar::Streamed module.
Here is the sample code.
my $tar2 = Archive::Tar::Streamed->new($filename);
$fil = $tar2->next;
while($fil) {
$_ = $fil->name;
if(m/abc\.txt/g) {
$fil->extract($outpath);
$fil = $tar2->next;
}
}
But the iterator is not working. It is looping the first file in the archive not moving to the next file.
Can someone tell me what mistake i've done here???
You put the call to next inside your if, so it's only executed if you extracted the file. There's nothing that modifies $fil inside the loop if the file is not extracted.
You can simplify your code quite a bit by just calling the iterator in the condition of the while loop. Also, you can use the =~ binding operator instead of storing the name in $_. And you do not want the /g regex modifier here. In scalar context, you use /g to loop through multiple matches in a string. Here, all you want is to know whether the string contains a match.
my $tar2 = Archive::Tar::Streamed->new($filename);
while(my $fil = $tar2->next) {
if($fil->name =~ m/abc\.txt/) {
$fil->extract($outpath);
}
}
Related
I have a sql wherein I am fetching few records, sorted by full name.
My requirement is to extract chunks of similar names and then do some operation on it.
Say, the sql returns some records containing names like [name1,name1,name2,name3,name3]
I need to split them to [name1,name1] , [name2] , [name3,name3]
I am able to do it, but I am not happy with my implementation as I have to call doSomethingWithNames()twice.
while (my $paRecs = $pStatementHandle->fetchall_arrayref({}, 3)){
foreach my $phRec(#{$paRecs}){
my $pCurrentName = $phRec->{'FULL_NAME'};
if ((scalar(#aParentRecords) eq 0) or ($aParentRecords[-1] eq $pCurrentName)){
push(#aParentRecords, $pCurrentName);
} else {
doSomethingWithNames(\#aParentRecords);
#aParentRecords= ();
push(#aParentRecords, $pCurrentName);
}
}
};
doSomethingWithNames(\#aParentRecords); # This should be inside while loop
I believe am running into this issue because while doesn't go into the loop for
the last iteration as fetch* returns undef.
Sounds basic PERL stuff, but tried many loop constructs with no luck.
Any pointer will be a great help
The trick is to postpone existing the loop by converting it into an infinite loop. This requires checking the loop-terminating condition (!$rows) twice, though.
my $rows = [];
my $prev_name = '';
my #group;
while (1) {
$rows = $sth->fetchall_arrayref({}, 3) if !#$rows;
if (!$rows || $rows->[0]->{FULL_NAME} ne $prev_name)
if (#group) {
do_something(\#group);
#group = ();
}
last if !$rows;
}
$prev_name = $rows->[0]->{FULL_NAME};
push #group, shift(#$rows);
}
I want to make a console and change the automatic completion function when I press tab but I want to differentiate between two cases:
If I press tab and the beginning of the command matches a list I supplied in an array, the auto complete will be according to this array.
If I press tab and the command isn't recognized from the list I supplied, I want the generic completion function to work, so t hat it will auto complete directories and file names in the current directory.
Is it possible?
Thanks a lot.
Edit: I'm trying to do it inside a perl script. I saw this example:
rl_attempted_completion_function
A reference to an alternative function to create matches.
The function is called with TEXT, LINE_BUFFER, START, and END. LINE_BUFFER is a current input buffer string. START and END are indices in LINE_BUFFER saying what the boundaries of TEXT are.
If this function exists and returns null list or undef, or if this variable is set to undef, then an internal function rl_complete() will call the value of $rl_completion_entry_function to generate matches, otherwise the array of strings returned will be used.
The default value of this variable is undef. You can use it as follows;
use Term::ReadLine;
...
my $term = new Term::ReadLine 'sample';
my $attribs = $term->Attribs;
...
sub sample_completion {
my ($text, $line, $start, $end) = #_;
# If first word then username completion, else filename completion
if (substr($line, 0, $start) =~ /^\s*$/) {
return $term->completion_matches($text,
$attribs->{'username_completion_function'});
} else {
return ();
}
}
...
$attribs->{attempted_completion_function} = \&sample_completion;
completion_matches(TEXT, ENTRY_FUNC)
What I want to do is that in case when tab is pressed it recognizes a substring from an array I provide, the auto completion will be from that array (if there are multiple matches it will give all of them like a regular unix console).
Otherwise, I want the auto completion to be file recognition.
The subroutine used internally by Term::ReadLine::Gnu to provide the default completion is filename_completion_function, which you can call directly from your custom subroutine:
use Term::ReadLine;
my $term = new Term::ReadLine 'MyTerm';
$term->Attribs->{'completion_entry_function'} = \&my_completion;
my $ans = $term->readline('How can I help you? ');
sub my_completion {
my ($text, $state) = #_;
if (my_test) {
return my_custom_stuff;
}
else {
return Term::ReadLine::Gnu->filename_completion_function($text, $state);
}
}
recently started doing perl. I'm reading old code and trying to rewrite some stuff. I've got a question here about hash references.
#declar anon hash ref that will be returned
my $store_hash = {};
foreach my $item (#list)
{
#this will iterate based on list
my $ret_hash = ops_getval($item, $user)
#do some magic here to map $ret_hash into $store_hash
}
ops_getval is a function that returns a type of ref hash. I want to insert those values into $store_hash. How should I approach this? Can I directly do
$store_hash = ops_getval($var1,$var2)
Much appreciated!
I think the standard way to do this is:
#$store_hash{ keys %$ret_hash } = values %$ret_hash;
This merges all of the hashes returned by all of the calls to ops_getval into $store_hash.
An alternate approach that might be clearer to the eye, possibly at the cost of a lot of redundant data copying:
%$store_hash = (%$store_hash, %$ret_hash);
You would do something like:
$store_hash->{$item} = $ret_hash
In general:
$hashref->{$key} = $value
See here for more: http://perldoc.perl.org/perlref.html#Using-References
To be clear, you can use a loop and get this done.
foreach ( keys%{ $ret_hash } ){
$store_hash->{ $_ } = $ret_hash->{ $_ } ;
}
So I have two files, one that contains my text, and another which I want to contain filter words. The one shown here is supposed to be the one with the curse words. Basically, what I'm doing is iterating through each of the words in the text file, and trying to compare them against the curse words.
sub filter {
$word_to_check = $_;
open ( FILE2, $ARGV[1]) || die "Something went wrong. \n";
while(<FILE2>) {
#cursewords = split;
foreach $curse (#cursewords) {
print $curse."\n";
if($word_to_check eq $curse) { return "BAD!";}
}
}
close ( FILE2 );
}
Here are the "curse words":
what is
Here is the text file:
hey dude what is up
But here's what's going wrong. As you can see, I've put a print statement to see if the curse words are getting checked correctly.
hey what
is
dude what
is
what what
is
is what
is
up what
is
I literally have no idea why this could be happening. Please let me know if I should post more code.
EDIT:
AHA! thanks evil otto. It seems I was getting confused with another print statement I had put in before. Now the problem remains: I think I'm not checking for string equality correctly. Here's where filter is getting called:
foreach $w( #text_file_words )
{
if(filter($w) eq "BAD!")
{
#do something here
}
else { print "good!"; }
}
EDIT 2: Nevermind, more stupidity on my part. I need to get some sleep, thanks evil otto.
change
$word_to_check = $_;
to
$word_to_check = shift;
You needed to collect arguments as an array in perl...
sub myFunction{
($wordToCheck) = #_; #this is the arg array, if you have more than one arg you just separate what's between the parenthesis with commas.
}
Can I do something like this in Perl? Meaning pattern match on a file name and check whether it exists.
if(-e "*.file")
{
#Do something
}
I know the longer solution of asking system to list the files present; read it as a file and then infer whether file exists or not.
You can use glob to return an array of all files matching the pattern:
#files = glob("*.file");
foreach (#files) {
# do something
}
If you simply want to know whether a file matching the pattern exists, you can skip the assignment:
if (glob("*.file")) {
# At least one file matches "*.file"
}
On Windows I had to use File::Glob::Windows as the Windows path separating backslashes don't seem to work perl's glob.
On *nix systems, I've used the following with good results.
sub filesExist { return scalar ( my #x = `ls -1a 2> /dev/null "$_[0]"` ) }
It replies with the number of matches found, or 0 if none. Making it easily used in 'if' conditionals like:
if( !filesExist( "/foo/var/not*there.log" ) &&
!filesExist( "/foo/var/*/*.log" ) &&
!filesExist( "/foo/?ar/notthereeither.log" ) )
{
print "No matches!\n";
} else {
print "Matches found!\n";
}
Exactly what patterns you could use would be determined by what your shell supports. But most shells support the use of '*' and '?' - and they mean the same thing everywhere I've seen. Of course, if you removed the call to the 'scalar' function, it would return the matches - useful for finding those variable file names.