in reply to Setting a Variable from filename

I thought the way to go was via an Array, I managed to read the files in from the Directory, and grep the entries to confirm the file I want is there, I can't seem to set the variable though.

As Corion said, it would be good if you could show the code, best would be as a Short, Self-Contained, Correct Example (see also How do I post a question effectively?) - for example, it can make a significant difference whether the files include the pathname or not.

But if I were to take a guess that the pathname is not included in the filename, you probably already have code something like my @wanted = grep {/_CF_/} @files;? In that case, you should be able to get the filename via $ScontrolFile = $wanted[0]; - but first, you might want to make sure that your grep did indeed match exactly one file by saying die "did not find exactly one _CF_ file (found: @wanted)" unless @wanted==1;.

Replies are listed 'Best First'.
Re^2: Setting a Variable from filename
by UpMaBigKilt (Initiate) on Apr 29, 2018 at 14:26 UTC
    Apologies, my current code is in work, however your response nails it for me I think, I hadn't considered using grep into a 2nd array where I then know the index will be [0].

    Thanks for the response.

      As always, There Is More Than One Way To Do It. If you're certain that the grep condition will always match exactly one element of @files:

      • $ScontrolFile = (grep {/_CF_/} @files)[0]; - create a "temporary" list and get its first element
      • ($ScontrolFile) = grep {/_CF_/} @files; - use assignment in list context
      • use List::Util qw/first/; $ScontrolFile = first {/_CF_/} @files; - use first from the core module List::Util, which has the advantage that it stops looking once it finds a match

      However, none of the above solutions provide protection against the case that @files does not contain exactly one string matching the pattern, which is why I suggested the extra array. <update> AnomalousMonk showed a way to add the check to the second of my examples above. To add a check to the other two, </update> you could theoretically search the array a second time, using grep in scalar context (if ( grep({/_CF_/} @files)!=1 ) { die ... }), but that's fairly wasteful and you'll have duplicated code (the grep block). Of course, you can also write an explicit loop:

      my $ScontrolFile; for my $file (@files) { if ( $file =~ /_CF_/ ) { die "more than one _CF_ file found in: @files" if defined $ScontrolFile; $ScontrolFile = $file; } } die "_CF_ file not found in: @files" unless defined $ScontrolFile;

      Update: Added check for >1 file in the above code, and see update in text.

      Well, you could grep your values into the same array if you wished:
      @files = grep { /_CF_/ } @files;
      Now, @files will contain only the file(s) matching the regex.

      But it is probably clearer (and easier to debug if you need) to grep the matching values into a new array and leave the original one untouched.

      Yet Another Way to capture first matching file, if any, and number of matching files concisely:

      c:\@Work\Perl\monks>perl -wMstrict -le "my @files = qw(xxx 1st_CF_xx CF__ 2nd_CF_yy CF); ;; my $n_CF_ = my ($first_CF_) = grep /_CF_/, @files; ;; print qq{number of _CF_ files: $n_CF_}; if ($n_CF_ == 1) { print qq{just one: '$first_CF_'}; } " number of _CF_ files: 2 c:\@Work\Perl\monks>perl -wMstrict -le "my @files = qw(xxx 1st_CF_xx CF__ CF); ;; my $n_CF_ = my ($first_CF_) = grep /_CF_/, @files; ;; print qq{number of _CF_ files: $n_CF_}; if ($n_CF_ == 1) { print qq{just one: '$first_CF_'}; } " number of _CF_ files: 1 just one: '1st_CF_xx' c:\@Work\Perl\monks>perl -wMstrict -le "my @files = qw(xxx yyy zzz); ;; my $n_CF_ = my ($first_CF_) = grep /_CF_/, @files; ;; print qq{number of _CF_ files: $n_CF_}; if ($n_CF_ == 1) { print qq{just one: '$first_CF_'}; } " number of _CF_ files: 0

      Update: Be aware that if no files match the grep condition in the example code above,  $first_CF_ is undefined.


      Give a man a fish:  <%-{-{-{-<