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

This node falls below the community's minimum standard of quality and will not be displayed.

Replies are listed 'Best First'.
Re: ActivePERL is the devil?
by Corion (Patriarch) on Jun 07, 2007 at 20:06 UTC

    Instead of blaming ActiveState, it helps to actually know about the module you use and the operating system environment your script runs on. The Shell module runs commands through the "current operating system shell", which, on Windows machines nowadays is cmd.exe, which uses the forward slash ("/") as command switch indicator and not as path separator.

    If you're afraid of using the well-tested modules to do file system operations from within Perl, most likely you will be able to use the backslash ("\\") as path separator on Windows machines. A far saner practice is to construct your file paths using the File::Spec module, that way you won't have to worry about the directory or file separators.

Re: ActivePERL is the devil?
by ikegami (Patriarch) on Jun 07, 2007 at 20:21 UTC

    The problem you are experiencing has nothing to do with ActivePerl (or even Perl), but with the invalid data you are supplying to the various Windows commands you are using. (You owe ActiveState an apology.)

    >copy dir1/file dir2 The syntax of the command is incorrect. >copy dir1\file dir2 1 file(s) copied. >del dir2/file Parameter format not correct - "file". >del dir2\file

    ++Corion. This post is a more visual version of his post.

Re: ActivePERL is the devil?
by shmem (Chancellor) on Jun 07, 2007 at 20:36 UTC
    Read the documentation of use. This is, if not bogus, then silly:
    use Shell qw( perl ); use Shell qw( dir ); use Shell qw( copy ); use Shell qw( del ); use Shell qw( cd );

    A use statement is performed once per module, and you pass it a list:

    use Shell qw( perl dir copy del cd );

    would be the right idiom. But perl? cd? AFAIK cd is a shell builtin, and perl has chdir.

    Probably the Shell->import() method will be invoked multiple times with your multiple use statements (I haven't tried), and your code thus is equivalent to

    use Shell qw( perl ); BEGIN { Shell->import( qw( dir ) ); } BEGIN { Shell->import( qw( copy ) ); } BEGIN { Shell->import( qw( del ) ); } BEGIN { Shell->import( qw( cd ) ); }

    but why invoke the same method multiple times with a single element, if you can invoke it once with a list?

    But there are far more gotchas in your script, none of those have to do anything with ActiveState. E.g. you should use File::Spec to portably assemble directory and file names into a path.

    --shmem

    _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                  /\_¯/(q    /
    ----------------------------  \__(m.====·.(_("always off the crowd"))."·
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
      cd? AFAIK cd is a shell builtin, and perl has chdir.
      He was using cd to change the current drive, not the current working directory. I don't know much about windows perl, so can't say whether that's a reasonable thing to try or not, or whether perl's chdir would have done as well.
        He was using cd to change the current drive, not the current working directory. I don't know much about windows perl, so can't say whether that's a reasonable thing to try or not...

        chdir will change drives as well as directories. But as I said previously, 'system("cd ...")' won't stay cd'd in your perl program, just in the command shell.

      and your code thus is equivalent to
      use Shell qw( perl ); BEGIN { Shell->import( qw( dir ) ); } BEGIN { Shell->import( qw( copy ) ); } BEGIN { Shell->import( qw( del ) ); } BEGIN { Shell->import( qw( cd ) ); }
      May be worse:
      BEGIN { require Shell; Shell->import( qw( perl ) ); } BEGIN { require Shell; Shell->import( qw( dir ) ); } BEGIN { require Shell; Shell->import( qw( copy ) ); } BEGIN { require Shell; Shell->import( qw( del ) ); } BEGIN { require Shell; Shell->import( qw( cd ) ); }
      Despite that only the first invocation of require compiles the module, it's still a sequence of invocations on the same function (require) with the same argument (Shell) within inside the very same file.

      Open source softwares? Share and enjoy. Make profit from them if you can. Yet, share and enjoy!

Re: ActivePERL is the devil?
by holli (Abbot) on Jun 07, 2007 at 19:52 UTC
Re: ActivePERL is the devil?
by Grundle (Scribe) on Jun 07, 2007 at 20:39 UTC
    This is a RTFM question but I'll bite anyways.

    File::Copy was mentioned before.
    use File::Copy; copy("oldfile", "newfile");
    So then all you need is the "dir". I noticed you are using system calls, that is unnecesary for these type of commands.

    try the following
    my @files = <some\\path\\here\\*>; #the * means all files in that directory #just in case you were confused.
    finally to delete a file use the following
    unlink($filename);
    If you want to set the context of your perl program to read from a particular directory without having to constantly put a $path + $filename then do the following
    chdir($path) or die "foo error message\n"; #now do some foo with $filename in this directory
    you just got served lol
Re: ActivePERL is the devil?
by ferreira (Chaplain) on Jun 07, 2007 at 21:55 UTC
    As the (yet non-official) maintainer of Shell as a CPAN distribution, I would like to defend there are good uses for Shell. But this does not seem one of them: all of the external programs you are calling have Perl builtins or core libraries to do it portably and faster.
    use Shell qw( perl ); # { local @ARGV = (...); do $filename; } use Shell qw( dir ); # glob() seems enough use Shell qw( copy ); # File::Copy use Shell qw( del ); # unlink use Shell qw( cd ); # chdir

    All the advices of the monks who replied to this node still apply. Some refactoring and moving filenames and tasks to configuration metadata driving the script could produce a much more robust and useful tool. But probably this isn't a priority or a need. So just two suggestions: (1) use / everywhere because Perl at Windows understand it very well unlike Windows itself; (2) maybe the Perl scripts "d:/perl/macc1" and "d:/perl/mmac3" can be converted to Perl modules with advantages to maintenance.

      use / everywhere because Perl at Windows understand it very well unlike Windows itself

      I've been told (on PerlMonks) that Windows system calls understand / just fine. It's the individual tools and shell commands that don't.

      In fact, it seems the shell tools understand / just fine if it's in quotes:

      G:\>md /test The syntax of the command is incorrect. G:\>md "/test" G:\>copy nul /test/file The syntax of the command is incorrect. G:\>copy nul "/test/file" 1 file(s) copied. G:\>dir /test Invalid switch - "". G:\>dir "/test" Volume in drive G is CLFS01-USR-N Volume Serial Number is 5C24-AC1F Directory of G:\test 2007/06/08 09:21 AM <DIR> . 2007/06/08 09:21 AM <DIR> .. 2007/06/08 09:21 AM 0 file 1 File(s) 0 bytes 2 Dir(s) 81,590,624,256 bytes free
      use Shell qw( perl ); # { local @ARGV = (...); do $filename; }
      Or,
      system $^X, 'otherscript', 'someargs';
      to ensure the use of the exact same copy of perl.

      Open source softwares? Share and enjoy. Make profit from them if you can. Yet, share and enjoy!

Re: ActivePERL is the devil?
by runrig (Abbot) on Jun 07, 2007 at 21:47 UTC
    system('cd ...') only changes directories within the command shell you've spawned, and when the shell is done and the program continues, you're still in the same directory you started in. As mentioned already, chdir is the function to use.
Re: ActivePERL is the devil?
by TGI (Parson) on Jun 08, 2007 at 21:00 UTC

    I think this is what you are trying to do:

    • Display a list of files in the current directory (or is it the tmp directory?)
    • Ask for the name of a file to process.
    • Test file name provided for existence.
    • Copy the file into a temporary location.
    • Run two scripts against the temp file.
    • Ask for input - keep the edits?
      • If yes copy the temp file over the original file
      • If no clean up temp file?
      • If no match, ask again.

    Others have pointed out some of the problems with this script, system("cd d:") doesn't effect the rest of the progrem, etc. Others remain unnoted so far (recursive function call to answer(), use of & on function calls).

    Here's my UNTESTED rough cut at a rewrite. Here's what I already know is wrong with it. I haven't enabled taint checking for the file names. I don't untaint the file names. There is almost certainly a better way to run those perl scripts against the target file. The subroutines need block comments describing what they do. Script paths are hardcoded in the body of the script and not in variables or constants at the top of the file. The temporary and base paths are specified in list form, which isn't too familiar to many people, I should really use File::Spec to parse normal paths. Finally it is UNTESTED code that features the dangerous unlink command. Despite all this, it may be a useful starting point for you.

    use strict; use warnings; use diagnostics; use File::Copy; use File::Spec; use Cwd; use Shell 'perl'; my @TEMP_PATH = ( 'D:', 'perl' ); my @BASE_PATH = ( 'D:', 'tmp' ); my $base_path = File::Spec->catdir( @BASE_PATH ); my $file = get_file_to_process( $base_path ); my $orig_file = File::Spec->catfile( @BASE_PATH, $file); my $temp_file = File::Spec->catfile( @TEMP_PATH, $file); process_file( $orig_file, $temp_file ); if ( keep_changes() ) { # Copy the editted file over the original copy( $temp_file, $orig_file ); } # Cleanup unlink $temp_file; # ------------------------------------ sub print_listing { my $dir_path = shift; my $curdir = cwd; # Change scripts working directory to TEMP_PATH chdir( $dir_path ); # Get a list of *.txt files using glob. # You could also use opendir to do this. while ( my $filename = glob('*.txt') ) { print "$filename\n"; } chdir( $curdir ); } sub get_file_to_process { my $base_path = shift; print_listing( $base_path ); print "Enter File Name to be converted.\n"; print "File should be in this directory.\n"; my $file = <STDIN>; chomp $file; # Test for existence die "File $file does not exist\n" unless -e $file; } sub process_file { my $orig_file = shift; my $temp_file = shift; # Copy the file into a temporary location. copy( $orig_file, $temp_file ) or die "Unable to create temp file $temp_file - $!\n"; # Here we edit the temporary file # instead of using it as a backup. print "Staring Edits...1."; perl "/perl/macc1", $temp_file; sleep 2; print ",13.\n"; perl "/perl/macc13", $temp_file; print "Edits complete.\n"; } sub keep_changes { print "Do you wish to keep the edits?\n"; print "Enter Yes or No.\n"; my $response = <STDIN>; chomp $response; while (1) { if ( $response =~ /^y(es)?$/i ) { return 1; } elsif ( $response =~ /^no?$/i ) { return; } else { print <<'END_MSG'; ===================================== You Have Entered and Incorrect Option Valid Options are [Y/N] ===================================== END_MSG } } }


    TGI says moo

Re: ActivePERL is the devil?
by Anonymous Monk on Jun 08, 2007 at 02:36 UTC
    perldoc -f chdir perldoc File::Spec perldoc File::Glob perldoc -f unlink perldoc File::Copy perldoc strict