I am interested only to know the value of key "DelayedAutoStart" and expect this code to work, but it print much more information. Can someone tell me what is wrong here?
use Win32::Registry;
use Data::Dumper;
$p = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion";
$p = "SYSTEM\\CurrentControlSet\\Services\\sppsvc";
$main::HKEY_LOCAL_MACHINE->Open($p, $CurrVer) ||
die "Open: $!";
$CurrVer->GetValues(\%vals);
#print Dumper(\%vals);
foreach $k (keys %vals) {
$key = $vals{$k};
if ($$key[0] == "DelayedAutoStart")
{
print "$$key[0] = $$key[2]\n";
}
}
RESULT:
ServiceSidType = 1
ErrorControl = 1
LaunchProtected = 1
DisplayName = #%SystemRoot%\system32\sppsvc.exe,-101
Start = 2
ImagePath = %SystemRoot%\system32\sppsvc.exe
Description = #%SystemRoot%\system32\sppsvc.exe,-100
DelayedAutoStart = 1
ObjectName = NT AUTHORITY\NetworkService
RequiredPrivileges = SeAuditPrivilege SeChangeNotifyPrivilege
SeCreateGlobalPrivilege SeImpersonatePrivilege
FailureActions = ÇQ☺ ♥ ¶ ☺ └È☺ ☺ Óô♦︎
DependOnService = RpcSs
Type = 16
Please add use strict and use warnings to your code. They will give you an error telling you that you're using the wrong kind of comparison operator. The == equality operator is for comparing numbers not strings. You need eq which does a string comparison.
Also, you're confusing matters rather by storing a hash value in a variable called $key and generally making things far more complicated than they need to be!
foreach my $key (keys %vals) {
if ($key eq "DelayedAutoStart")
{
print "$key = $vals{$key}[2]\n";
}
}
But, of course, you can just look up the value in the hash directly. No need to iterate over the keys. That's pretty much the point of using a hash :-)
my $key = 'DelayedAutoStart';
if (exists $vals{$key}) {
print "$vals{$key} = $vals{$key}[2]\n";
}
Related
The propose of the script to grep some value from some data table in the ASCII files.
I modified the
script which I posted yesterday.
Now it barely works. I wonder if it is the proper way to move a file handle in this way.
The usage is still the same
myscript.pl targetfolder/*> result.csv
F is my file handle.
The argument I passed to the subroutine is the scalar $_, which is used by the if condition. When I want to move downward in my subroutine next if 1..4 will not work, so I repeat $a = <F>; a few times to achieve moving file handle downward.
But I think this is not a proper way to move the same file handle both in my main code and my subroutine. I am not sure it will really go through every line. I need your advice.
myscript.pl
#Report strip
use warnings;
use strict;
##Print the title
Tfms2();
##Print the title
print "\n";
#ff = <#ARGV>;
foreach $ff ( #ff ) {
open (F, $ff);
#fswf = #fschuck = #fsxpos = #fsypos = #fsdev = #csnom = "";
#cswf = #cschuck = #csxpos = #csypos = #csnom = ""; # is there an efficient way?
while (<F>) {
Mfms2();
Mfms3();
}
$r = 1;
while ( $r <= $#fswf ) { # because #fsws is the largest array
Cfms3();
print "\n";
$r++;
}
close (F);
}
##==========================================================================================
##Subs
##==========================================================================================
##FS II
sub Tfms2 {
print "FS_Wafer,FS_ChuckID,FS_pos_X,FS_pos_Y,FS_deviation,CS_Wafer,CS_ChuckID,CS_pos_X,CS_pos_Y,CS_NofWafer_Ident_Spot";
}
sub Mfms2 {
if ( /^F\sM\sSTATISTICS\sII$/ ) {
$a = (<F>);
$a = (<F>);
$a = (<F>);
$a = (<F>);
$a = (<F>);
$a = (<F>);
$a = (<F>);
$a = (<F>);
$r = 1;
#b = "";
while ( $a !~ /\+\-/ ) {
chomp $a;
#b = split / *\| */, $a;
$fswf[$r] = $b[1];
$fschuck[$r] = $b[2];
$fsxpos[$r] = $b[3];
$fsypos[$r] = $b[4];
$fsdev[$r] = $b[5];
$r++;
$a = (<F>);
#b = "";
}
}
}
##FS III
sub Mfms3 {
if ( /^F\sM\sSTATISTICS\sIII$/ ) {
$a = (<F>);
$a = (<F>);
$a = (<F>);
$a = (<F>);
$a = (<F>);
$a = (<F>);
$a = (<F>);
$a = (<F>);
$r = 1;
#b = "";
while ( $a !~ /\+\-/ ) {
chomp $a;
#b = split / *\| */, $a;
$cswf[$r] = $b[1];
$cschuck[$r] = $b[2];
$csxpos[$r] = $b[3];
$csypos[$r] = $b[4];
$csnom[$r] = $b[5];
$r++;
$a = (<F>);
#b = "";
}
}
}
sub Cfms3 {
print "$fswf[$r],$fschuck[$r],$fsxpos[$r],$fsypos[$r],$fsdev[$r],";
print "$cswf[$r],$cschuck[$r],$csxpos[$r],$csypos[$r],$csnom[$r],";
}
You have forgotten to tell us what the program is supposed to do, so it's very hard to be any help. There might be more information in your previous question, but we don't all read every question here and you don't even include a link to your previous question.
The answer to your question is that you can use seek() to move to an arbitrary position in a file. You might also find it useful to look at tell() which can tell you where you currently are in a file.
But I don't think that information will be particularly helpful to you as you seem rather confused about what you're trying to do. If you were to explain your task in a bit more detail, then I strongly suspect that we could help you (and I also suspect that help would largely involve rewriting your code from scratch). But until you give us details, all we can do is to point out some of the more obvious problems with your code.
You should always include use strict and use warnings in your code.
I don't think that #ff = <#ARGV> does what you think it does. I think you want #ff = #ARGV instead. And, even then, that feels like you're copying #ARGV pointlessly.
Having an array (#ff) and a scalar ($ff) with the same name is going to confuse someone at some point. And, more generally, you need to put more effort into naming your variables clearly.
Please use the three-argument version of open() along with lexical filehandles. You should also always check the return code from open() - open my $fh, "<", $ff or die "Could not open $ff: $!".
Your lines like #fswf=#fschuck=#fsxpos=#fsypos=#fsdev=#csnom="" aren't doing what you think they are doing. You end up with a lot of arrays each of which contain a single element. Better to just declare the arrays with my - Perl will create them empty (my (#fswf, #fschuck, #fsxpos, ...)).
If you really need to skip eight lines when reading from your file then it's much clearer to write: $a = <F> for 1 .. 8.
You are making heavy use of global variables. There's a good reason why this goes against software engineering best practices. It makes your code far more fragile than it needs to be.
All in all, you seem to be guessing at a solution here, and that's never a good approach. As I said above, we'd like to help you, but without a lot more information that's going to be almost impossible.
Update: Looking at your code a bit more closely, I see that you are storing the data that you parse from the files in a number of arrays. Each array contains data from a single column of the input file and in order to get all of the data from a single row, you need to access each of these arrays using the same index value. This isn't a very good idea. Splitting linked data across different variables is a recipe for disaster. A far better idea would be to store each record in a hash (where the key would denote the data item that is stored) and to store references to all of these hashes in an array. This brings all of your data together in a single variable.
Updated update: I don't know enough about your data to be sure, but here's the kind of approach I would take. I've only parsed the data and then used Data::Dumper to display the parsed data structure. Producing better output is left as an exercise for the reader :-)
#!/usr/bin/perl
use strict;
use warnings;
use feature 'say';
use Data::Dumper;
#ARGV or die "Usage: $0 file [file...]\n";
# Define two list of keys for the different types
my %cols = (
II => [qw(wf chuck xpos ypos dev)],
III => [qw(wf chuck xpos ypos nom)],
);
my #data; # To store the parsed data
my $cur_type; # Keep track of the current type of record
while (<>) {
# Look for a record header and determine which type of
# record we're dealing with (I think 'II' or 'III').
if (/^F M STATISTICS (III?)$/) {
$cur_type = $1;
next;
}
# Skip lines that are just headers/footers
next if /\+[-=]/;
# Skip lines that don't include data
next unless /\d/;
chomp;
# Remove the start and end of the line
s/^\|\s+//;
s/\s+\|$//;
# Store the data in a hash with the correct keys
# for this type of record
my %rec;
#rec{#{$cols{$cur_type}}} = split /\s+\|\s+/;
# Store a reference to our hash in #data
push #data, \%rec;
}
# Dump the contents of #data
say Dumper \#data;
I know that there have been multiple posts about this topic already, but I have not found them to be helpful for my particular case.
When I run this excerpt of code
my $bandName = '';
my $rrh_sth = $dbh->prepare("SELECT serial....");
$rrh_sth->execute;
my $int_hash = $rrh_sth->fetchall_hashref('serial');
delete $_->{serial} for values %$int_hash;
foreach my $s ( keys %$int_hash ) {
if ( $values[6] eq $s ) {
#$bandName = #{%$int_hash}{$s};
$bandName = $int_hash ->{$s};
my $ulink = getFreq($bandName, "u");
my $dlink = getFreq($bandName, "d");
my $status = "active";
print Dumper (
$bandName,
$values[0],
$values[8],
$values[7],
$values[6],
$values[11],
$values[10],
$values[3],
$values[4],
$values[5],
$dlink,
$ulink
);
}
}
I keep getting the key and the value for the particular serial, represented by $s. I know that I have to de-reference int_hash, but I am not sure how now that the methods that I have tried do not work.
$VAR1 = {
'rrhName' => 'MCD59'
};
$VAR2 = 'MCO57';
$VAR3 = 'R-S-S:1-0-1';
$VAR4 = 'scb';
$VAR5 = '12NT46000050';
$VAR6 = undef;
$VAR7 = '109786038';
$VAR8 = 'MCO: 976 2x5W AC';
$VAR9 = 'enabled';
$VAR10 = '1';
$VAR11 = ''; #EDITED
$VAR12 = ''; #EDITED
In general, when I have a reference, I need to dereference it to get to the slices, but in the case of $VAR1, when I go to my database to see the value being inserted its telling me the position of $VAR1 in memory, which is not what I thought I was asking for.
Your $int_hash is a hash reference, and you dereference it correctly into a hash, %$int_hash, to then retrieve its keys. The obtained key is then also used correctly to get the corresponding value, $int_hash->{$s}.
However, as the Dumper output shows, the value associated with the key $s is itself a hash reference. Since a reference itself is a scalar we can always assign it as a value to a key, which is how complex (nested) data structures are built. See perldsc for a cookbook and for references in general see perlreftut for a tutorial and perlref for a reference.
In short, you only need to keep dereferencing
$int_hash->{$s}->{'rrhName'}; # or,
$int_hash->{$s}{'rrhName'}; # or even
$int_hash->{$s}{rrhName};
The second and third lines are syntax shortcuts, explained in the above pages.
Either of these will return the value in the nested hash, MCD59.
You are committing the sin of doing a linear search for a key in the hash %$int_hash that matches $values[6]. You don't access arrays that way. It would look like this
my $values_6;
for my $i ( 0 .. $#values ) {
if ( $i == 6 ) {
$values_6 = $values[$i];
}
}
You need to discard your for loop and simply access the hash element directly. Combining that with accessing the value of the second-level hash, your code should look like this
my $band_name;
if ( my $band = $int_hash->{$values[6]} ) {
$band_name = $band->{rrhName};
my $ulink = getFreq($band_name, 'u');
my $dlink = getFreq($band_name, 'd');
my $status = 'active';
}
I need Perl's auto-increment magic for strings, but some strings (such as those composed entirely of digits) are interpreted as numbers and a normal increment is performed instead. How would I force Perl to treat a value passed to ++ as a string?
Here's the related question about how auto incrementing works: Autoincrementing letters in Perl
Like the docs explained, basically you need the variable to
match the regex /^[a-zA-Z]*[0-9]*\z/ and
only be used in string contexts.
Because you have variables that don't match the regex, those ones will be treated as numbers. You can write your own increment function to get your desired functionality. Here's an idea I had about how it could work to get you started.
#!/usr/bin/perl
use strict;
use warnings;
my $test = "1000";
for (0..100) {
$test = increment($test);
}
print $test . "\n";
$test = "M2V3";
for (0..100) {
$test = increment($test);
}
print $test . "\n";
sub increment {
my ($str) = #_;
my #letters = reverse split //, $str;
my $add = "";
my $increment = 1;
my $result = "";
for my $let (#letters) {
if ( $increment == 1 ) {
++$let;
}
if ( $let =~ /(.)(.)/ ) {
$add = $2;
$increment = 1;
} else {
$add = $let;
$increment = 0;
}
$result = $add . $result;
}
return $result;
}
This outputs:
1101
M3F4
I didn't calculate to confirm that M3F4 is the correct result but it seems close.
I have the following multidimensional hash variable
my %billingMember ;
$billingMember{1}->{'useremail_quota'} = 10;
$billingMember{1}->{'useremail_blockedquota'} = 5;
$billingMember{2}->{'useremail_quota'} = 10;
$billingMember{2}->{'useremail_blockedquota'} = 5;
How can i parse the variable %billingMember ?
ie I need to get each value like
$billingMember{1}->{'useremail_quota'},
$billingMember{1}->{'useremail_blockedquota'} ,
$billingMember{2}->{'useremail_quota'}, ....
Here 1& 2 is just for example, it will dynamic
So i think, we need to use foreach or for
Some samples taken from http://perldoc.perl.org/perldsc.html#HASHES-OF-HASHES :
foreach $family ( keys %HoH ) {
print "$family: { ";
for $role ( keys %{ $HoH{$family} } ) {
print "$role=$HoH{$family}{$role} ";
}
print "}\n";
}
(Edit : only kept the one which will probably be useful in your case)
I have the following string:
$str = "list
XYZ
status1 : YES
value1 : 100
status2 : NO
value2 : 200
Thats all";
I want to convert it into a hash using a function which takes this string as input and returns a hash with status1 as key and YES as value for example.
How to do so?
And how to reference the returned hash?
Like always, there's more than one way to do it. Here come five.
Pure regular expressions (YEAH!)
I think this is the coolest one. The regex returns a list of all captures which is exactly the list we want to initialize the hash with:
my %regex = $str =~ /(\S+)\s*:\s*(\S+)/g;
Iterative
This is the most straightforward way for most programmers, I think:
my #lines = split /\R/ => $str;
my %iterative = ();
for (#lines) {
next unless /(\S+)\s*:\s*(\S+)/;
$iterative{$1} = $2;
}
Nothing to explain here. I first split the string in lines, then iterate over them, leaving out lines that don't look like foo : bar. Done.
List processing
Writing everything as a big list expression feels a little bit hackish, but maybe this is interesting to learn more ways to express stuff:
my %list = map { /(\S+)\s*:\s*(\S+)/ and $1 => $2 }
grep { /:/ }
split /\R/ => $str;
Read from right to left: Like in the example above we start with splitting the string in lines. grep filters the lines for : and in the final map I transform matching line strings in a list of length two, with a key and a value.
List reducing
Non-trivial use-cases of List::Util's reduce function are very rare. Here's one, based on the list approach from above, returning a hash reference:
my $reduced = reduce {
$a = { $a =~ /(\S+)\s*:\s*(\S+)/ } unless ref $a;
$a->{$1} = $2 if $b =~ /(\S+)\s*:\s*(\S+)/;
return $a;
} grep { /:/ } split /\R/ => $str;
State machine
Here's a funny one with regex usage for white-space separation only. It needs to keep track of a state:
# preparations
my $state = 'idle';
my $buffer = undef;
my %state = ();
my #words = split /\s+/ => $str;
# loop over words
for my $word (#words) {
# last word was a key
if ($state eq 'idle' and $word eq ':') {
$state = 'got_key';
}
# this is a value for the key in buffer
elsif ($state eq 'got_key') {
$state{$buffer} = $word;
$state = 'idle';
$buffer = undef;
}
# remember this word
else {
$buffer = $word;
}
}
Just for fun (note that I recommend using one of memowe's) here is one that (ab)uses the YAML:
#!/usr/bin/env perl
use strict;
use warnings;
use YAML;
my $str = "list
XYZ
status1 : YES
value1 : 100
status2 : NO
value2 : 200
Thats all";
$str = join "\n", grep { /:/ } split "\n", $str;
my $hash = Load "$str\n";
#!/usr/bin/perl
use warnings;
$\="\n";
sub convStr {
my $str = $_[0];
my %h1=();
while ($str =~m/(\w+)\s+:\s+(\w+)/g) {
$h1{$1} =$2;
}
return \%h1;
}
my $str = "list
XYZ
status1 : YES
value1 : 100
status2 : NO
value2 : 200
Thats all";
my $href=convStr($str);
foreach (keys(%$href)) {
print $_ , "=>", $href->{$_};
}
On running this, I get:
status2=>NO
value1=>100
status1=>YES
value2=>200
my %hhash;
my #lines = split /\s+\n/, $str;
foreach (#lines)
{
$_=~s/^\s+//g;
if(/:/)
{
$key=(split(/:/))[0];
$value=(split(/:/))[1];
$hhash{$key}=$value;
}
}