in reply to creating valid paths for Path::Tiny

In addition to what soonix posted about chomping newlines a recommendation for troubleshooting and general validation is to use file tests to check for the existence of files. They can save you a lot of hair pulling in this situation.

foreach my $file (@files) { if( -f $file) { print "<$file> is a plain file.\n"; } else { print "<$file> is not a plain file.\n"; } }

This can be shortened with the conditional operator:

use strict; use warnings; my @files = qw( file1 test.pl.txt file3 4); push @files, "file5 "; foreach my $file (@files){ print "<$file> is ", -f $file ? '' : 'not ', "a plain file.\n"; }

I encourage you to consider using strict also.

Replies are listed 'Best First'.
Re^2: creating valid paths for Path::Tiny
by soonix (Abbot) on Aug 14, 2018 at 17:38 UTC
    Because I like Path::Tiny, I wanted to add that it does include methods for these tests, too. Then I noticed that the author himself says
    Use -f instead if you really mean to check for a plain file.

    Another ++ I'd give for your example of enclosing the file name in visible delimiters like "<$file>".

    However, use 5.011 implies strict (although use states 5.012 as the first with this property) so OP already is "strict-compliant" ;-)

      Path::Tiny seems like a really useful module. Thanks for pointing out that it includes file tests.

      Your observation about 'use' seems like it would be a good bug report for Perldocs.

Re^2: creating valid paths for Path::Tiny
by Aldebaran (Chaplain) on Aug 14, 2018 at 21:33 UTC

    Thanks all for comments. I'm getting decent partial results, with a manifest that got a newline in it as other processes added filenames to it. Instead of editing out the blank line, I tried to code around it.

    $ cat 1.manifest 2.create.bash 11.clone.pl 1.initialize.pl 1.manifest 1.med 1.meditation 1.pop 1.qy 1.rings 2.med 5.create.sh 5.unicode 3.create.bash $

    Caller is getting more complicated, and I send a reference of the main data hash to archive1() to embellish on:

    $ cat 4.archive.pl #!/usr/bin/perl -w use 5.011; use lib "template_stuff"; use utils2; use Path::Tiny; use utf8; use open qw/:std :utf8/; use Data::Dumper; # initializations that must precede main data structure my $fspecfile = File::Spec->rel2abs(__FILE__); ### does this^^^ have a Path::Tiny equivalent? ## turning things to Path::Tiny my $path1 = Path::Tiny->cwd; say "path1 is $path1"; my $title = $path1->basename; say "base is $title"; # script parameters my %vars = ( init_dir => $path1, title => $title, script_file => $fspecfile, ); # caller my $rvars = \%vars; my $return1 = archive1( $rvars ); # returns created dir chdir( $return1 ); system("pwd"); system("find ."); __END__ $

    I highlighted a code question in the above listing and am puzzled that in the following, a key/value pair for $vars{"grandfather"} seems not to be created. In other words, the hash does not seem to be extensible in the way I thought all hashes in perl were:

    $ cat utils2.pm package utils2; require Exporter; use utils1; use utf8; use open qw/:std :utf8/; use Data::Dumper; our @ISA = qw(Exporter); our @EXPORT = qw( archive1 ); sub archive1 { use warnings; use 5.011; use Path::Tiny; my $rvars = shift; my %vars = %$rvars; say Dumper $rvars; $vars{"grandfather"} = $vars{"init_dir"}->parent(); my $file1 = "1.manifest"; my $from = path( $vars{"grandfather"}, $file1 ); say "from is $from"; my @files = $from->lines_utf8( { chomp => 1 } ); say Dumper $rvars; say "files are @files"; my $tempdir = Path::Tiny->tempdir('backup_XXXXXX'); say "temp dir is $tempdir"; my $readme = $tempdir->child( 'grandmother', 'README.txt' )->touchpa +th; say "read me is $readme"; my $grand_dir = $readme->parent; chdir $grand_dir; foreach my $item (@files) { say "item is <<$item>>"; next if ($item eq ""); my $abs = path( $vars{"grandfather"}, $item ); say "abs is <$abs>"; if ( -d $abs ) { say "$abs is a directory"; } if ( -f $abs ) { say "$item is a plain file"; #syntax is from -> to my $return = path($abs)->copy( $grand_dir, $item ); if ( $item =~ m/\.(pl|sh)$/ ) { $return->chmod(0755); } say "return is $return"; } } my $b = $tempdir; return $b; } 1; $

    Output:

    $ ./4.archive.pl path1 is /home/bob/1.scripts/pages/1.qy base is 1.qy $VAR1 = { 'init_dir' => bless( [ '/home/bob/1.scripts/pages/1.qy', '/home/bob/1.scripts/pages/1.qy', '', '/home/bob/1.scripts/pages/', '1.qy' ], 'Path::Tiny' ), 'title' => '1.qy', 'script_file' => '/home/bob/1.scripts/pages/1.qy/4.archive.p +l' }; from is /home/bob/1.scripts/pages/1.manifest $VAR1 = { 'init_dir' => bless( [ '/home/bob/1.scripts/pages/1.qy', '/home/bob/1.scripts/pages/1.qy', '', '/home/bob/1.scripts/pages/', '1.qy' ], 'Path::Tiny' ), 'title' => '1.qy', 'script_file' => '/home/bob/1.scripts/pages/1.qy/4.archive.p +l' }; files are 2.create.bash ... 5.unicode 3.create.bash temp dir is /tmp/backup_MKb3nU read me is /tmp/backup_MKb3nU/grandmother/README.txt item is <<2.create.bash>> abs is </home/bob/1.scripts/pages/2.create.bash> 2.create.bash is a plain file return is /tmp/backup_MKb3nU/grandmother/2.create.bash ... item is <<5.unicode>> abs is </home/bob/1.scripts/pages/5.unicode> /home/bob/1.scripts/pages/5.unicode is a directory item is <<>> item is <<3.create.bash>> abs is </home/bob/1.scripts/pages/3.create.bash> 3.create.bash is a plain file return is /tmp/backup_MKb3nU/grandmother/3.create.bash /tmp/backup_MKb3nU . ./grandmother ./grandmother/1.initialize.pl ./grandmother/3.create.bash ./grandmother/5.create.sh ./grandmother/1.manifest ./grandmother/2.create.bash ./grandmother/README.txt ./grandmother/11.clone.pl cannot remove path when cwd is /tmp/backup_MKb3nU for /tmp/backup_MKb3 +nU: at /usr/share/perl/5.26/File/Temp.pm line 1583. $

    Fishing for tips....

      ### does this^^^ have a Path::Tiny equivalent?

      Yes. It is the absolute method.

      #!/usr/bin/env perl use strict; use warnings; use Path::Tiny; my $abs = path(__FILE__)->absolute; print "$abs\n";

      Datz_cozee75 wrote:

      my $path1 = Path::Tiny->cwd; say "path1 is $path1"; my $title = $path1->basename; say "base is $title"; # script parameters my %vars = ( init_dir => $path1, title => $title, script_file => $fspecfile, ); ... $vars{"grandfather"} = $vars{"init_dir"}->parent();
      I highlighted a code question in the above listing and am puzzled that in the following, a key/value pair for $vars{"grandfather"} seems not to be created. In other words, the hash does not seem to be extensible in the way I thought all hashes in perl were:

      Hi Datz_cozee75. If you have a look at perldata you can read about how hashes work. A hash is an associative array of scalar values. That means the only thing you can store in a hash is a string, a number or a reference. In the code section above you seem to be trying to call the parent() method against the value of $vars{"init_dir"}. Did you get any warnings when you ran this program?

      Update: I tried a small test of your code above and it works. I realized after I posted and looked more closely at the output you posted that the hash value is holding a reference to the path object. Why do you say that a key/value pair for $vars{"grandfather"} is not created? It looks like the following line in your output shows that the key value pair was created.

      from is /home/bob/1.scripts/pages/1.manifest

      Since you asked for tips I suggest starting with a much smaller program and build functionality until you have your final result. Smaller, simpler functions allow you to test and get it working before adding functionality. Also, your tested code can be kept separate from new code that way.

      Here is my test script:

      use warnings; use strict; use Path::Tiny; use feature 'say'; use Data::Dumper; my $path1 = Path::Tiny->cwd; say "path1 is $path1"; my $title = $path1->basename; say "base is $title"; # script parameters my %vars = ( init_dir => $path1, title => $title, ); $vars{"grandfather"} = $vars{"init_dir"}->parent(); print Dumper(\%vars); print "vars-grandfather : ", $vars{"grandfather"}->basename, "\n"; print "vars-grandfather : ", $vars{"grandfather"}; __DATA__ path1 is C:/usr/pm base is pm $VAR1 = { 'init_dir' => bless( [ 'C:/usr/pm', 'C:\\usr\\pm', 'C:', '/usr/', 'pm' ], 'Path::Tiny' ), 'title' => 'pm', 'grandfather' => bless( [ 'C:/usr', 'C:\\usr' ], 'Path::Tiny' ) }; vars-grandfather : usr vars-grandfather : C:/usr