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

#!/usr/bin/perl # untitled1.pl open(shortcuts,"location.txt" || die"Can't open the stinkin' file"); @file = <shortcuts>; close(shortcuts); foreach $line (@file) { chomp($line); system(`$line\n`); } location.txt c:/program files/netscape/communicator/program/netscape.exe c:/Program Files/Netscape/Communicator/Winamp/winamp.exe c:/Program Files/Netscape/Communicator/Program/AIM/aim.exe

Replies are listed 'Best First'.
Re: loading
by btrott (Parson) on Jul 08, 2000 at 07:55 UTC
    Other posters have pointed out problems. Here's another, which jjhorner also alluded to.

    You wrote:

    open(shortcuts,"location.txt" || die"Can't open the stinkin' file" +);
    This is wrong. Why do you have the || there? The || has higher precedence than the comma, so you're actually OR-ing "location.txt" with the die statement. "location.txt" will always be true, so that die will never get invoked, even if the open fails. Which is, I presume, when you wanted it to be invoked.

    Instead, use something like this:

    open SH,"location.txt" or die"Can't open the stinkin' file";
    This will die if the open fails.
(jcwren) RE: loading
by jcwren (Prior) on Jul 08, 2000 at 17:11 UTC

    This program won't do what you want for a number of reasons:

    1. In spite of people telling you to use -w and use strict; there are no 'my' keywords in front of the @file or $line variables, so the program won't even try to run.
    2. system() does not do what you expect. Unless the program you're calling explicitly detaches itself as a process internally, only the first program will execute, because system() will be waiting for the program to execute before starting the next item.
    3. I don't know about ActiveState and any of the other builds, but the build of 5.005_03 under NT, if you don't encapsulate paths with spaces in quotes, the program won't be found. You either need to include quotes in the string, programatically, before calling system(), alter your data to have quotes around the strings in the 'location.txt' file, or use (gag!) 8.3 filename nomenclature. NT is smart enough, however, to not care about the direction of the path slashes (CMD.EXE cares, but the system internally does not, and really hasn't since about DOS 5.0 or so), and we can add the quotes programmatically, so we'll do that.
    4. The @file and $line variables could be eliminated. I was debating if there was any merit in reading the lines before executing them, and I can't find any compelling reason to do so before executing them.
    5. You could optionally include the data with the program. Depending on the programming methodology you subscribe to, some call for separating the data from the program to the extent that you should be using mySQL with a browser interface to update the paths. Or, if this is a utility script, and you don't like unnecessary data files cluttering up your disk, and you want to make *sure* there is some data within the program, you can include it as part of the program, in a __DATA__ section. I'll take this tact, since you're probably not going to be making a CPAN submission.

    So, with all this in mind, here is a version that should do what you want. It works on my NT 4.0/SP6a system using Perl 5.005_03, with no problems. (side note here: The actual path to the perl executable is irrelevant. However, you need *something* there so that the compiler picks up the -w flag. Don't be concerned that there is no '/usr/bin/perl' path on your system.)
    #!/usr/bin/perl -w use strict; while (<DATA>) { chomp; system ("start \"$_\" \"$_\"") && die "Can't execute $_\n"; } __DATA__ c:/program files/netscape/communicator/program/netscape.exe c:/Program Files/Netscape/Communicator/Winamp/winamp.exe c:/Program Files/Netscape/Communicator/Program/AIM/aim.exe
    Why does this work, you might ask, after telling you that system() won't return until the called program completes? Because we're taking advantage of a little known fact that the 'shell' (such as it is) supports the 'start' keyword, which allows processes to be detached from the calling shell. The first parameter is the name of the program in the DOS box, and the second parameter is the program to execute. We technically could leave the first one blank, but I chose not to as I was debugging, and I saw no reason to leave it out. Supposedly, we could have omitted it, and used the /PGM switch, but I was getting errors. Since adding the window name fixed it, I didn't have any reason to pursue it any further.

    In this version, chomp() is required because the 'shell' gets very upset if you pass a carriage return into it. What you'll end up with is 3 open DOS boxes, with the window name as the name of the program you're trying to execute.

    Hopefully, this should do what you want. For testing, I have to change the names of the paths, and I don't have AIM installed (I used FreeCell instead), but I do have the rest. It all started up for me, just fine. Hopefully, it will work for you.

    --Chris

    e-mail jcwren
Re: loading
by jjhorner (Hermit) on Jul 08, 2000 at 07:37 UTC

    Try wrapping your code in tags.

    As Ozymandias said, use strict and -w. Also, if you are going to report an error, you might want to know why the error occurred: use $! to report the error message.

    I heard someone say once that you should use all caps to differentiate filehandles from other words in your code.

    Why use "|| die" inside the parenthesis? Isn't it just fine outside of them?

    You should also error check your 'system' call, but since 'system' returns 0 as the successful response, use && instead of ||.

    #!/usr/bin/perl -w # untitled1.pl use strict; open(SHORTCUTS,"location.txt") || die"Can't open file: $!"; @file = <SHORTCUTS>; close(SHORTCUTS) || die "Can't close file: $!"; foreach $line (@file) { system($line) && die "Can't execute $line: $!"; }
    J. J. Horner
    Linux, Perl, Apache, Stronghold, Unix
    jhorner@knoxlug.org http://www.knoxlug.org/
    
Re: loading
by Ozymandias (Hermit) on Jul 08, 2000 at 06:17 UTC
    Number one, get in the habit of using -w, and use strict;.

    Try it this way. Others will add more changes.

    #!/usr/bin/perl -w # untitled1.pl use strict; open(shortcuts,"location.txt" || die"Can't open the stinkin' file"); @file = ; close(shortcuts); foreach $line (@file) { # The chomp isn't necessary. And you don't need the backticks. system($line); } location.txt c:/program files/netscape/communicator/program/netscape.exe c:/Program Files/Netscape/Communicator/Winamp/winamp.exe c:/Program Files/Netscape/Communicator/Program/AIM/aim.exe

    - Ozymandias