Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

Using the perl debugger to look at a renaming files function

by Aldebaran (Curate)
on Feb 04, 2021 at 03:12 UTC ( [id://11127875]=perlquestion: print w/replies, xml ) Need Help??

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

Hello Good Netizens

I started a meditation with Renaming all files in a directory that got more response than I anticipated, and now that I've thought about the questions that were raised, I would like to visit the same problem space in SopW. In meditations, we might focus on what unites us; over here we might squabble about implementation, vendors, "best ways", and more importantly, deal with questions, and I shall pose a few.

I've watched this twice now: Ricardo Signes 2020 perl conference, and I would like to see if I can pull off the same things he's doing. I think I've set up the playing field appropriately:

First we have this from caller:

## this function is to be debugged using the perl debugger my $return2 = make_initial_captions; say "return2 is $return2";

And then I've stubbed out a function that has access to the primary data structure:

sub make_initial_captions { use 5.016; use warnings; use POSIX; use Path::Tiny; use Encode; use open OUT => ':encoding(UTF-8)', ':std'; use Data::Dumper; my $rvars = shift; my %vars = %$rvars; print Dumper $rvars; my $image_path = $vars{"to_images"}; my $caption_path = $vars{"eng_captions"}; return "nothing yet"; }

In these minimal changes to what was working, I've managed to make it *not work* as I present, so it will be a good candidate for debugging. Here's what my terminal says as I invoke caller:

$ ./1.debug.11.pl Subroutine debug1::getcwd redefined at /usr/share/perl/5.30/Exporter.p +m line 66. at template_stuff/debug1.pm line 397. title is 1.debug.1 path1 is /home/hogan/6.scripts/1.debug.1 abs is /home/hogan/6.scripts/1.debug.1/1.debug.11.pl Can't use an undefined value as a HASH reference at template_stuff/deb +ug1.pm line 35. $ pwd /home/hogan/6.scripts/1.debug.1 $ ls 1.debug.11.pl 1.debug.11.pl.bak template_stuff $

Caller and library are about 500 lines together, so I'll show them once between readmore tags:

$ cat 1.debug.11.pl #!/usr/bin/perl -w use 5.011; use lib "template_stuff"; use debug1; use Path::Tiny; use utf8; use Encode; use open OUT => ':encoding(UTF-8)', ':std'; # initializations that must precede main data structure my $ts = "template_stuff"; my $images = "aimages"; my $captions = "captions"; my $ruscaptions = "ruscaptions"; ## turning things to Path::Tiny # decode paths my $abs = path(__FILE__)->absolute; my $path1 = Path::Tiny->cwd; my $title = $path1->basename; $abs = decode( 'UTF-8', $abs ); $path1 = decode( 'UTF-8', $path1 ); $title = decode( 'UTF-8', $title ); say "title is $title"; say "path1 is $path1"; say "abs is $abs"; my $path2 = path( $path1, $ts ); # page params my %vars = ( title => $title, headline => undef, ts => 'template_system', place => 'Between Portland and Boise', base_url => 'http://www.merrillpjensen.com', css_file => "${title}1.css", header => path( $path2, "hc_input2.txt" ), footer => path( $path2, "footer_center3.txt" ), body => path( $path2, "rebus7.tmpl" ), code_tmpl => path( $path2, "code2.tmpl" ), oitop => path( $path2, "oitop.txt" ), oibottom => path( $path2, "oibottom.txt" ), to_images => path( $path2, $images ), eng_captions => path( $path2, $captions ), rus_captions => path( $path2, $ruscaptions ), translations => path( $path2, 'translations' ), bottom => path( $path2, "bottom1.txt" ), css_path => $path2, css_remote => 'css', print_module => 0, print_script => "1", script_file => $abs, module_tmpl => path( $path2, "code3.tmpl" ), apache_rt => '/var/www/html', html_dir => 'perlmonks', image_dir => 'pm_image', book => 'The perl debugger', chapter => 'with images and captions', ); my $rvars = \%vars; ## this function is to be debugged using the perl debugger my $return2 = make_initial_captions; say "return2 is $return2"; my $return = create_page($rvars); say "return is $return"; say $vars{"base_url"} . '/' . $vars{"html_dir"} . '/' . "$return"; __END__ $ cd template_stuff/ $ cat debug1.pm package debug1; require Exporter; use utils1; our @ISA = qw(Exporter); our @EXPORT = qw( get_content write_body get_html_filename create_html_file write_script write_bottom write_header write_footer write_module get_tiny create_page put_page get_tiny make_russian_captions make_initial_captions ); sub make_initial_captions { use 5.016; use warnings; use POSIX; use Path::Tiny; use Encode; use open OUT => ':encoding(UTF-8)', ':std'; use Data::Dumper; my $rvars = shift; my %vars = %$rvars; print Dumper $rvars; # put a break point here my $image_path = $vars{"to_images"}; my $caption_path = $vars{"eng_captions"}; return "nothing yet"; } sub make_russian_captions { use 5.011; use warnings; use POSIX qw(strftime); use Path::Tiny; use Encode; use open OUT => ':encoding(UTF-8)', ':std'; my $rvars = shift; my %vars = %$rvars; my $munge = strftime( "%d-%m-%Y-%H-%M-%S\.txt", localtime ); my $in_path = path( $vars{translations}, $munge )->touchpath; my $lang = 'ru'; #system("pwd >$in_path"); works my @matching2; opendir( my $hh, $vars{eng_captions} ) or die "death $!\n"; while ( defined( $_ = readdir($hh) ) ) { if (m/txt$/) { push( @matching2, $_ ); } } #important to sort @matching2 = sort @matching2; say "matching are @matching2"; my $rus_munge = path( $vars{translations}, "trans." . $munge ); say "rus_munge is $rus_munge"; # open file for writing my $fh = path($in_path)->openw_utf8; foreach (@matching2) { my $eng_path = path( $vars{eng_captions}, $_ ); say $fh "##$_##"; my $rus_path = path( $vars{rus_captions}, $_ )->touchpath; say "rus_path is $rus_path"; my $content = path($eng_path)->slurp_utf8; $content =~ s/^\s+|\s+$//g; say $fh "$content"; system("trans :$lang file://$eng_path >$rus_path"); } print "Get other translations(y/n)?: "; my $prompt = <STDIN>; chomp $prompt; if ( $prompt eq ( "y" | "Y" ) ) { my @translators = qw /yandex bing/; for my $remote (@translators) { my $trans_munge = path( $vars{translations}, "$remote." . $munge + ); ## use trans shell say "getting translation from $remote"; system("trans :$lang -e $remote file://$in_path >$trans_munge"); } } return "nothing yet"; } sub get_tiny { use 5.011; use warnings; use Net::SFTP::Foreign; use Config::Tiny; use Data::Dumper; my $ini_path = qw( /home/hogan/Documents/html_template_data/6.values +.ini ); say "ini path is $ini_path"; my $sub_hash = "my_sftp"; my $Config = Config::Tiny->new; $Config = Config::Tiny->read( $ini_path, 'utf8' ); say Dumper $Config; # -> is optional between brackets my $domain = $Config->{$sub_hash}{'domain'}; my $username = $Config->{$sub_hash}{'username'}; #my $password = $Config->{$sub_hash}{'password'}; my $port = $Config->{$sub_hash}{'port'}; #dial up the server say "values are $domain $username $port"; my $sftp = Net::SFTP::Foreign->new( $domain, #more => '-v', user => $username, port => $port, #password => $password ) or die "Can't connect: $!\n"; return $sftp; } sub create_page { use 5.011; #use trans1; use Net::SFTP::Foreign; use Encode; use open OUT => ':encoding(UTF-8)', ':std'; #create html page my $rvars = shift; my %vars = %$rvars; my $sftp = get_tiny(); say "object created, back with caller"; my $html_file = get_html_filename( $sftp, $rvars ); $vars{html_file} = $html_file; print "Make rus captions(y/n)?: "; my $prompt1 = <STDIN>; chomp $prompt1; if ( $prompt1 eq ( "y" | "Y" ) ) { my $ref_cap = make_russian_captions($rvars); } my $fh = create_html_file($html_file); my $remote_dir = $html_file; $remote_dir =~ s/\.html$//; say "remote_dir is $remote_dir"; $vars{remote_dir} = $remote_dir; $rvars = \%vars; ## why so necessary? # create header my $rhdr = write_header($rvars); print $fh $$rhdr; $vars{refc} = get_content($rvars); #print_aoa($refc); my $body = write_body( $rvars, $vars{refc} ); print $fh $$body; my $rftr = write_footer($rvars); print $fh $$rftr; if ( $vars{"print_script"} ) { my $script = write_script($rvars); print $fh $$script; } if ( $vars{"print_module"} ) { my $module = write_module($rvars); print $fh $$module; } my $rhbt = write_bottom($rvars); print $fh $$rhbt; close $fh; print "Put file to server(y/n)?: "; my $prompt2 = <STDIN>; chomp $prompt2; if ( $prompt2 =~ /y/i ) { put_page( $sftp, $rvars ); } return $html_file; } sub put_page { use 5.016; use utils1; use Net::SFTP::Foreign; use Encode; use open OUT => ':encoding(UTF-8)', ':std'; use Data::Dumper; my ( $sftp, $rvars ) = (@_); my %vars = %$rvars; ###### beginning overhaul 10-2020 # quick and easy print Dumper $rvars; ###### say " %%%%% change"; my $path1 = path( $vars{"apache_rt"}, $vars{"html_dir"}, $vars{"image_dir"}, $vars{"title"} ); say "path1 is $path1"; $sftp->mkpath($path1) or warn "mkpath1 failed $!\n"; #load html file to server my $path2 = path( $vars{"apache_rt"}, $vars{"html_dir"} ); say "path2 is $path2"; $sftp->setcwd($path2) or warn "setcwd1 failed $!\n"; $sftp->put( $vars{html_file} ) or die "html put failed $!\n"; $sftp->ls; #load css file to server my $path3 = path( $vars{"apache_rt"}, $vars{"css_remote"} ); say "path3 is $path3"; my $path6 = path( $vars{"css_path"}, $vars{"css_file"} ); say "path6 is $path6"; $sftp->mkpath($path3) or warn "mkpath3 failed $!\n"; $sftp->setcwd($path3) or warn "setcwd for path3 failed $!\n"; say " -----"; print $sftp->cwd(), "\n"; say " -----"; $sftp->put( $path6, $vars{"css_file"} ) or warn "css put failed $@\n +"; # upload images $sftp->setcwd($path1) or warn "setcwd for images failed $!\n"; print $sftp->cwd(), "\n"; say " %%%%% end 10-2020 change"; #print Dumper $rvars; my $ref_content = $vars{refc}; my @AoA = @$ref_content; for my $i ( 0 .. $#AoA ) { my $a = path( $vars{to_images}, $AoA[$i][0] ); say "a is $a"; my $b = $a->basename; say "b is $b"; $sftp->put( $a, $b ) or warn "AoA put failed $@\n"; } undef $sftp; return; } sub get_content { use 5.010; my $rvars = shift; my %vars = %$rvars; my $refimg = get_images($rvars); my $refcaps = get_utf8_text( $rvars, $vars{"eng_captions"} ); my $refruscaps = get_utf8_text( $rvars, $vars{"rus_captions"} ); my $aoa = [ $refimg, $refcaps, $refruscaps ]; my $b = invert_aoa($aoa); return ($b); } sub get_images { use 5.011; my $rvars = shift; my %vars = %$rvars; my @filetypes = qw/jpg gif png jpeg GIF/; my $pattern = join '|', map "($_)", @filetypes; my @matching2; opendir my $hh, $vars{to_images} or warn "warn $!\n"; while ( defined( $_ = readdir($hh) ) ) { if ( $_ =~ /($pattern)$/i ) { push( @matching2, $_ ); } } #important to sort @matching2 = sort @matching2; return \@matching2; } sub get_utf8_text { use 5.010; use HTML::FromText; use Path::Tiny; use utf8; use open qw/:std :utf8/; ### Passing in #reference to main data structure and directory for captions my ( $rvars, $dir ) = (@_); my %vars = %$rvars; say "dir is $dir"; opendir my $eh, $dir or warn "can't open dir for utf8 captions $!\n +"; while ( defined( $_ = readdir($eh) ) ) { next if m/~$/; next if -d; if (m/txt$/) { my $file = path( $dir, $_ ); my $guts = $file->slurp_utf8; my $temp = text2html( $guts, urls => 1, email => 1, paras => 1, ); # surround by divs my $oitop = $vars{"oitop"}; my $oben = $oitop->slurp_utf8; my $oibottom = $vars{"oibottom"}; my $unten = $oibottom->slurp_utf8; my $text = $oben . $temp . $unten; #say "text is $text"; $content{$_} = $text; } } closedir $eh; #important to sort my @return; foreach my $key ( sort keys %content ) { #print $content{$key} . "\n"; push @return, $content{$key}; } return \@return; } sub write_body { use warnings; use 5.011; use Text::Template; use Encode; my $rvars = shift; my $reftoAoA = shift; my %vars = %$rvars; my @AoA = @$reftoAoA; my $body = $vars{"body"}; my $template = Text::Template->new( ENCODING => 'utf8', SOURCE => $body ) or die "Couldn't construct template: $!"; my $return = ""; for my $i ( 0 .. $#AoA ) { $vars{"file"} = $AoA[$i][0]; $vars{"english"} = $AoA[$i][1]; my $ustring = $AoA[$i][2]; $vars{"russian"} = $ustring; my $result = $template->fill_in( HASH => \%vars ); $return = $return . $result; } return \$return; } sub write_bottom { use strict; use Text::Template; my ($rvars) = shift; my %vars = %$rvars; my $footer = $vars{"bottom"}; my $template = Text::Template->new( SOURCE => $footer ) or die "Couldn't construct template: $!"; my $result = $template->fill_in( HASH => $rvars ); return \$result; } sub get_html_filename { use Net::SFTP::Foreign; use File::Basename; use Cwd; use 5.01; binmode STDOUT, ":utf8"; my ( $sftp, $rvars ) = (@_); my %vars = %$rvars; # get working directory my $word = $vars{"title"}; say "word is $word"; my $path3 = path( $vars{"apache_rt"}, $vars{"html_dir"} ); say "path3 is $path3"; my $ls = $sftp->ls( "$path3", wanted => qr/$word/ ) or warn "unable to retrieve " . $sftp->error; print "$_->{filename}\n" for (@$ls); my @remote_files = map { $_->{filename} } @$ls; say "files are @remote_files"; my $rref = \@remote_files; my $filetype = "html"; my $old_num = highest_number( $rref, $filetype, $word ); print "old num is $old_num\n"; my $new_num = $old_num + 1; my $html_file = $word . $new_num . '.' . $filetype; return $html_file; } sub create_html_file { my $html_file = shift; open( my $fh, ">>:encoding(UTF-8)", $html_file ) or die("Can't open $html_file for writing: $!"); return $fh; } sub write_header { use Text::Template; use 5.011; use warnings; my $rvars = shift; my %vars = %$rvars; # get time my $now_string = localtime; $vars{"date"} = $now_string; my $headline = join( ' ', $vars{"book"}, $vars{"chapter"} ); $vars{"headline"} = $headline; my $header = $vars{"header"}; my $template = Text::Template->new( ENCODING => 'utf8', SOURCE => $header, ) or die "Couldn't construct template: $!"; my $result = $template->fill_in( HASH => \%vars ); say "result is $result"; return \$result; } sub write_footer { use Text::Template; my ($rvars) = shift; my %vars = %$rvars; my $footer = $vars{"footer"}; my $template = Text::Template->new( SOURCE => $footer ) or die "Couldn't construct template: $!"; my $result = $template->fill_in( HASH => $rvars ); return \$result; } sub write_script { use Text::Template; use 5.010; use utf8; my ($rvars) = shift; my %vars = %$rvars; my $tmpl = $vars{"code_tmpl"}; say "tmpl is $tmpl"; my $file = $vars{"script_file"}; my $text = do { open my $fh, '<:raw:encoding(UTF-8)', $file or die "$file: $!"; local $/; <$fh>; }; my %data = ( 'script', $text ); my $template = Text::Template->new( SOURCE => $tmpl ) or die "Couldn't construct template: $!"; my $result = $template->fill_in( HASH => \%data ); return \$result; } sub write_module { use 5.010; use File::Spec; use Text::Template; use utf8; my ($rvars) = shift; my %vars = %$rvars; my $tmpl = $vars{"module_tmpl"}; say "tmpl is $tmpl"; my $file = File::Spec->rel2abs(__FILE__); my $text = do { open my $fh, '<:raw:encoding(UTF-8)', $file or die "$file: $!"; local $/; <$fh>; }; my %data = ( 'module', $text ); my $template = Text::Template->new( SOURCE => $tmpl ) or die "Couldn't construct template: $!"; my $result = $template->fill_in( HASH => \%data ); return \$result; } 1; $

Line 397 has to be the most innocent looking thing I've ever seen:

  use Cwd;

, so the mystery is real to me, and the task authentic. What I want to do in this function is read in the names of the files in the order that would have occured had it been done by ls | . Order is super important for this exercise. Q1) When I

use POSIX;

, do I have a canonical way to decide what alphanumeric order is in a world teemimg with things that could be filenames and what might be competing ways to decide precedence? jwkrahn brought up an example of a name with a question mark in the middle that seemed to confound ls | . I'm left wondering how many types of weird filenames out there might confound a script, too.

$ pwd /home/hogan/6.scripts/1.debug.1/template_stuff/captions $ touch caption{01..07}.txt $ ls caption01.txt caption03.txt caption05.txt caption07.txt caption02.txt caption04.txt caption06.txt $

What I would like this routine to do is take the filename from the nth file and store it in the nth caption. One should then see

$ pwd /home/hogan/6.scripts/1.debug.1/template_stuff/aimages $ ls 'Screenshot from 2021-02-03 15-20-48.png' 'Screenshot from 2021-02-03 15-22-28.png' 'Screenshot from 2021-02-03 15-23-42.png' 'Screenshot from 2021-02-03 15-24-01.png' 'Screenshot from 2021-02-03 15-25-04.png' 'Screenshot from 2021-02-03 15-29-08.png' 'Screenshot from 2021-02-03 15-32-57.png' $

So these would populate the content of the caption files.

and then, I would like to be able to step through that with the debugger, where I'm fishing fo tips. Be aware that I have bothered to take first steps, but, as this shows, it's a lot of content and pretty new (to me). Since the terminal doesn't lie, I see I approached it backwards:

$ history | grep perldeb 1980 perldoc perldebguts 1981 perldoc perldebug 1982 perldoc perldebtut 1990 history | grep perldeb $

Thanks for your comment,

Replies are listed 'Best First'.
Re: Using the perl debugger to look at a renaming files function
by Fletch (Bishop) on Feb 04, 2021 at 04:13 UTC

    Another handy trick (if you don't mind modifying the source and are focusing on a particular piece of code) is to set $DB::single to a true value which will act as if you'd put a breakpoint at that line.

    Alternatives to the debugger proper: check out Smart::Comments which will let you get debugging dumps when you run using that module (it's a moderately ebil source filter, but unless you've enabled the module they're just plain text comments). Or use Log::Log4perl and liberally sprinkle DEBUG(qq{intresting value:}, $interesting) statements throughout your code; when you no longer need them, just reduce the log level to (e.g.) INFO instead and those disappear (but they're still there and can be turned back on at will by tweaking a config/log level).

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

Re: Using the perl debugger to look at a renaming files function (on Debuggers References)
by eyepopslikeamosquito (Archbishop) on Feb 04, 2021 at 05:48 UTC

    Though you've watched the Ricardo Signes How to use the Perl debugger talk twice (while I've not yet watched it once) I'd just like to throw a general word of caution that becoming an expert in using the Perl debugger may not be the best use of your time if your goal is to improve as a developer.

    A few debugger quotes from some famous programmers:

    • merlyn : I'm not into debugging. I can't recall ever invoking the Perl debugger except to try out snippets of code at a prompt ... But never for debugging. (Larry is also like this, I'm told.) merlyn again : If the code the client throws at you needs a debugger to trace it through, I'd argue it's not maintainable.
    • Linus Torvalds : I do not condone single-stepping through code to find the bug ... Without a debugger you have to look at the level above sources. At the meaning of things. You have to understand what the program does. Not just that particular line. (See also: Linus Torvalds wikiquote).
    • Brian Kernighan and Rob Pike : As personal choice, we tend not to use debuggers beyond getting a stack trace or the value of a variable or two. One reason is that it is easy to get lost in details of complicated data structures and control flow; we find stepping through a program less productive than thinking harder and adding output statements and self-checking code at critical places. Clicking over statements takes longer than scanning the output of judiciously-placed displays. It takes less time to decide where to put print statements than to single-step to the critical section of code, even assuming we know where that is. More important, debugging statements stay with the program; debugging sessions are transient.
    • Rob Pike : Ken taught me that thinking before debugging is extremely important. If you dive into the bug, you tend to fix the local issue in the code, but if you think about the bug first, how the bug came to be, you often find and correct a higher-level problem in the code that will improve the design and prevent further bugs.
    • Uncle Bob Martin : Using a debugger is a code smell. I consider debuggers to be a drug -- an addiction. Programmers can get into the horrible habit of depending on the debugger instead of on their brain. IMHO a debugger is a tool of last resort.
    • John Graham-Cumming : For me, a debugger is (almost) always the wrong tool. And people who habitually use debuggers are making a big mistake, because they don't truly understand their code. I suspect that the same people who use debuggers all the time, are the same people who don't unit test their code.
    • Daniel Lemire. The author of Python, Guido van Rossum, has been quoted as saying that he uses print statements for 90% of his debugging.
    • Damian Conway urges you to add new test cases before you start debugging. After all, if the original test suite didn't report this bug, then that test suite was broken ... so fix the test suite first by adding tests that cause it to fail ... once the test suite is detecting the problem correctly, then you'll be able to tell when you've correctly fixed the actual bug, because the tests will once again fall silent.

    See Also

    References Added Later

      Linus Torvalds : I do not condone single-stepping through code to find the bug ... Without a debugger you have to look at the level above sources. At the meaning of things. You have to understand what the program does. Not just that particular line.

      I find myself wanting to retort, but that's not the right spirit. My claim rather is that this fulfills Torvalds' criterion:

      $ perl -d 1.debug.11.pl Loading DB routines from perl5db.pl version 1.55 Editor support available. Enter h or 'h h' for help, or 'man perldebug' for more help. main::(1.debug.11.pl:12): my $ts = "template_stuff"; DB<1> c + title is 1.debug.1 path1 is /home/hogan/6.scripts/1.debug.1 abs is /home/hogan/6.scripts/1.debug.1/1.debug.11.pl debug1::make_initial_captions(template_stuff/debug1.pm:42): 42: my $iter = $image_path ->iterator; DB<1> c + /home/hogan/6.scripts/1.debug.1/template_stuff/aimages/image3.png Path::Tiny::CODE(0x55823b1ce7d8)(/usr/share/perl5/Path/Tiny.pm:1179): 1179: my $next; DB<1> c + /home/hogan/6.scripts/1.debug.1/template_stuff/aimages/image4.png Path::Tiny::CODE(0x55823b1ce7d8)(/usr/share/perl5/Path/Tiny.pm:1179): 1179: my $next; DB<1> c + /home/hogan/6.scripts/1.debug.1/template_stuff/aimages/image6.png Path::Tiny::CODE(0x55823b1ce7d8)(/usr/share/perl5/Path/Tiny.pm:1179): 1179: my $next; DB<1> c + /home/hogan/6.scripts/1.debug.1/template_stuff/aimages/image1.png Path::Tiny::CODE(0x55823b1ce7d8)(/usr/share/perl5/Path/Tiny.pm:1179): 1179: my $next; DB<1> c + /home/hogan/6.scripts/1.debug.1/template_stuff/aimages/image5.png Path::Tiny::CODE(0x55823b1ce7d8)(/usr/share/perl5/Path/Tiny.pm:1179): 1179: my $next; DB<1> c + /home/hogan/6.scripts/1.debug.1/template_stuff/aimages/image0.png Path::Tiny::CODE(0x55823b1ce7d8)(/usr/share/perl5/Path/Tiny.pm:1179): 1179: my $next; DB<1> c + /home/hogan/6.scripts/1.debug.1/template_stuff/aimages/image2.png Path::Tiny::CODE(0x55823b1ce7d8)(/usr/share/perl5/Path/Tiny.pm:1179): 1179: my $next; DB<1> c + return2 is nothing yet ini path is /home/hogan/Documents/html_template_data/6.values.ini ... return is 1.debug.15.html http://www.merrillpjensen.com/perlmonks/1.debug.15.html Debugged program terminated. Use q to quit or R to restart, use o inhibit_exit to avoid stopping after program termination, h q, h R or h o to get additional info. DB<1> q + $

      All of the people you quote are elite professional programmers as opposed to the intermediate that I am, who makes useful software for his own communications, holding it all together with bubble-gum and tie-wire. I really like the price, too. Getting output adds to an already happy day....

        Though I've never met Linus, I suspect retorting to him would be futile, given his parting shot was "Because I'm a bastard, and proud of it!". :) Update: It seems Linus is now a reformed character (from Organizational Culture (Part V): Behavior).

        Based on the code you posted, I feel the most relevant quotes for you are from Pike, Martin, and especially Graham-Cumming:

        I suspect that the same people who use debuggers all the time are the same people who don't unit test their code
        and Conway:
        fix the test suite first by adding tests that cause it to fail ... once the test suite is detecting the problem correctly, then you'll be able to tell when you've correctly fixed the actual bug, because the tests will once again fall silent

        That is, with clean, well-designed code with unit tests there should be less need to fire up the debugger. I suggest you at least consider the option of replacing hours of never-ending crack-pipe debugging sessions with enjoyable creative hours of Test Driven Development.

Re: Using the perl debugger to look at a renaming files function
by haj (Vicar) on Feb 04, 2021 at 09:11 UTC
    Hello Aldebaran,

    The Perl debugger is a wonderful tool, and I use it quite often - whenever I find it is the appropriate tool for the task. Before I fire up the debugger, I always stare at the messages, the code and at the docs, and in your example this turns out to be sufficient to see what's happening. In your case, the messages you get are quite helpful, and the debugger is unlikely to get more:

    You seem to be wondering about the warning Subroutine debug1::getcwd redefined...?

    Line 397 has to be the most innocent looking thing I've ever seen:
    use Cwd;

    According to the docs, Cwd exports a function 'getcwd'. If this is a redefinition, then look for another module which exports a function with the same name. Here's a sample utils1.pm (you didn't include this) which is sufficent to cause that message to appear:

    # A sample utils1.pm use Path::Tiny 'cwd'; 1;

    Next, the code terminates with the message:

    Can't use an undefined value as a HASH reference at template_stuff/debug1.pm line 35.

    That's also quite obvious: You're calling the sub without any parameters, but it expects one which can be used as a HASH reference in line 35 of debug1.pm:

      my $rvars = shift;
      my %vars  = %$rvars;

    Unfortunately, I just don't understand your Q1 and can't help you there:

    , do I have a canonical way to decide what alphanumeric order is in a world teemimg with things that could be filenames and what might be competing ways to decide precedence?

    But anyway:

    I'm left wondering how many types of weird filenames out there might confound a script, too.

    None, if your script reads a directory like it should (either using Path::Tiny or opendir/readdir), and if you don't make wrong assumptions about which characters can appear in a path.

    Finally, some general advice if you want to get good answers here:

    • Keep your code concise: Eliminate stuff which isn't relevant to your question. For example, I'm not going to install Net::SFTP::Foreign to get it even compiled.
    • Keep your own example complete. utils1.pm is missing.
    • Make separate code tags for different files. Having to split your stuff at the $ cat lines is annoying.
      > If this is a redefinition, then look for another module which exports a function with the same name.

      Perl keeps the information where (file, line and package) a function was declared before exporting.

      There multiple ways to introspect° it, I chose Devel::Peek out of laziness.

      Introducing the line 123 in the code just before the redefinition happens will show the culprit.

      DB<121> use Cwd DB<122> use Devel::Peek DB<123> Dump \&getcwd if defined &getcwd SV = IV(0x3458550) at 0x3458560 REFCNT = 1 FLAGS = (TEMP,ROK) RV = 0xdc79e0 SV = PVCV(0xe02188) at 0xdc79e0 REFCNT = 11 FLAGS = (DYNFILE,HASEVAL) COMP_STASH = 0xd54290 "Cwd" # PACKAGE START = 0x2985788 ===> 1 ROOT = 0x29ade90 GVGV::GV = 0xdc7b48 "Cwd" :: "_win32_cwd" # NAME FILE = "c:/Perl_524/lib/Cwd.pm" # FILE DEPTH = 0 FLAGS = 0x5000 OUTSIDE_SEQ = 633 PADLIST = 0x29d5aa8 PADNAME = 0x29bb378(0x29ca0a8) PAD = 0xdc79f8(0x29c8968) 1. 0xdc7a28<1> (634,635) "$pwd" OUTSIDE = 0xd540e0 (UNIQUE) DB<124>

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery

      °) the B backend has methods for it, some modules offer wrapper for it:

      The Perl debugger is a wonderful tool, and I use it quite often - whenever I find it is the appropriate tool for the task. Before I fire up the debugger, I always stare at the messages, the code and at the docs, and in your example this turns out to be sufficient to see what's happening.

      I simply thought that this problem might be a good way for me to get my feet wet with the debugger. I thought it might bring me close to perl's machine model.

      That's also quite obvious: You're calling the sub without any parameters, but it expects one which can be used as a HASH reference in line 35 of debug1.pm:

      Yes indeed. I needed to change that line with caller:

      my $rvars = \%vars; ## this function is to be debugged using the perl debugger my $return2 = make_initial_captions($rvars); say "return2 is $return2";
      Keep your code concise: Eliminate stuff which isn't relevant to your question. For example, I'm not going to install Net::SFTP::Foreign to get it even compiled.

      Let's consider this. I know that we're encouraged to come up with an SSCCE, but this is not, nor can it easily be made so. It's an html templating system that has evolved according to my needs. I've tried to make a distribution of it, but I couldn't manage how to deal with filesystems on github. What would you use instead of Net::SFTP::Foreign?

      Keep your own example complete. utils1.pm is missing.

      This was my effort to be concise. I don't see how the use statements in subroutines affects other modules:

      Update: put module source between readmore tags

      Question: what use statements can be removed from everything I've posted?

      This routine has a breakpoint now:

      sub make_initial_captions { use 5.016; use warnings; use POSIX; use Path::Tiny; use Encode; use open OUT => ':encoding(UTF-8)', ':std'; use Data::Dumper; my $rvars = shift; my %vars = %$rvars; #print Dumper $rvars; my $image_path = $vars{"to_images"}; my $caption_path = $vars{"eng_captions"}; # put a break point here $DB::single = 1; return "nothing yet"; }

      , and, I got to see some values at this mark:

      $ perl -d 1.debug.11.pl Loading DB routines from perl5db.pl version 1.55 Editor support available. Enter h or 'h h' for help, or 'man perldebug' for more help. Subroutine debug1::getcwd redefined at /usr/share/perl/5.30/Exporter.p +m line 66. at template_stuff/debug1.pm line 400. debug1::BEGIN() called at template_stuff/debug1.pm line 400 eval {...} called at template_stuff/debug1.pm line 400 require debug1.pm called at 1.debug.11.pl line 4 main::BEGIN() called at template_stuff/debug1.pm line 400 eval {...} called at template_stuff/debug1.pm line 400 main::(1.debug.11.pl:12): my $ts = "template_stuff"; DB<1> n + main::(1.debug.11.pl:13): my $images = "aimages"; DB<1> c + title is 1.debug.1 path1 is /home/hogan/6.scripts/1.debug.1 abs is /home/hogan/6.scripts/1.debug.1/1.debug.11.pl debug1::make_initial_captions(template_stuff/debug1.pm:43): 43: return "nothing yet"; ... DB<3> p $vars{to_images} + /home/hogan/6.scripts/1.debug.1/template_stuff/aimages DB<4> p $vars{eng_captions} + /home/hogan/6.scripts/1.debug.1/template_stuff/captions DB<5> c + return2 is nothing yet ini path is /home/hogan/Documents/html_template_data/6.values.ini ...[normal execution] return is 1.debug.13.html http://www.merrillpjensen.com/perlmonks/1.debug.13.html Debugged program terminated. Use q to quit or R to restart, use o inhibit_exit to avoid stopping after program termination, h q, h R or h o to get additional info. DB<5> q + $

      It then executed to the end and behaved.

        Let's consider this. I know that we're encouraged to come up with an SSCCE, but this is not, nor can it easily be made so. It's an html templating system that has evolved according to my needs.

        Your questions were not about HTML templating systems, they were about manipulating lists of filenames. It would have been easy enough for you to construct an SSCCE which demonstrated a single, isolated problem. If your SSCCE did not exhibit the same problem as your larger code then the problem is somewhere else in your larger code and you need to determine that first.

        Question: what use statements can be removed from everything I've posted?

        Let's just look at this one package. You have use 5.010; and  use 5.011; in package utils1; - the former is quite obviously superfluous and should be removed (it does nothing and if read in isolation is potentially misleading).

        In some of the subroutines you use strict, in others warnings and in still others both (or neither). This inconsistency is perplexing to say the least. Far better to use both throughout: either within your package or in the scope enclosing it.

        In subroutine invert_aoa you use 5.010; but there is apparently nothing in this sub which requires that version. What is the statement doing here? Remove this.

        In subroutine highest_number you use both File::Basename and Cwd but then do absolutely nothing with them. Remove these.

        In subroutines print_aoa and print_hash you use 5.011; but there is apparently nothing in these subs which requires that version. What is the statement doing here? Remove this.

        Other things which aren't helping you: inconsistent indenting, use of the special variables $a and $b as lexicals, using a package name with all lowercase when it isn't a pragma and exporting everything.

        If you had created an SSCCE then it is probable that some or perhaps even all of these issues would not appear in it. That would make the work of everyone reading the SSCCE much easier and therefore make them (ie. me) much more likely to offer help. There are therefore 2 benefits. Firstly the construction of the SSCCE helps you to hone down the problem better and in doing so may even solve it for you. Secondly, it allows others to see the actual problem you are having without wading through hundreds of lines of unnecessary code.


        🦛

        I simply thought that this problem might be a good way for me to get my feet wet with the debugger.

        Fair enough. But then - I couldn't find a question related to how to use the debugger in your post.

        I thought it might bring me close to perl's machine model.

        Oh, I don't think the debugger will help here. The Perl debugger may help to understand Perl code you're currently maintaining, or maybe understand the interaction with a CPAN module in cases where its documentation isn't clear enough - but it doesn't go into Perl's guts.

        I know that we're encouraged to come up with an SSCCE, but this is not, nor can it easily be made so.

        Then, why show the code? What do you expect us to do with it?

        Question: what use statements can be removed from everything I've posted?

        That question has already been answered by other monks, so let me add just a general remark: It is of little use to have use statements within a subroutine. Typically you see them near the top of the file so that it is easy to spot the dependencies of your code.

        This routine has a breakpoint now:

        Good - that's one of the methods to get a breakpoint into the source. Since you've already read the docs about the Perl debugger, you should be aware that you could also have done it like that:

        $ perl -d 1.debug.11.pl DB<1>f debug1.pm DB<2>b 42

        You could, of course, also b debug1::make_initial_captions and then step to line 42.

Re: Using the perl debugger to look at a renaming files function
by LanX (Saint) on Feb 04, 2021 at 03:48 UTC
    First of all I have to say it's a really bad idea to stuff so many use repeatedly into subs.

    Your post is neither short nor concise, so please forgive me if I missed the point, but

    > I would like to be able to step through that with the debugger

    Did you try to set breakpoints or watch conditions?

    If not, please try h b , h w and h h to learn more.

    See perldebtut and perldebug for more.

    HTH :)

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11127875]
Approved by GrandFather
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others learning in the Monastery: (6)
As of 2024-04-19 03:08 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found