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

I'm writing a perl script to processes a bunch of files in the current directory and I want to ensure that the script does not process itself. Is there a way to ensure that the script knows its own name (just in case someone changes the name of the script)?

Thanks,

Jeremiah

Replies are listed 'Best First'.
Re: Get My Own Name
by Abigail-II (Bishop) on Feb 04, 2004 at 15:59 UTC
    Ignore the people who come with $0. If people can have renamed the program, they could have given it an additional link as well, and no $0 is going to protect you against that. Besides, what if people rename the program after it was started?

    Don't rely on the file, use the inode number instead. To get the inode number of your program, add __DATA__ to the end of it, and use:

    my $inode_number = (stat DATA) [1]; # And not fileno!

    Abigail

      To expand on what Abigail-II points out here, once you have the inode number of your script, you can then test the inode numbers in a similar manner for each file you are operating on and test that they are not equal.

      Just thought I'd clarify that point...

      I like that solution!


      Peter L. Berghold -- Unix Professional
      Peter at Berghold dot Net
         Dog trainer, dog agility exhibitor, brewer of fine Belgian style ales. Happiness is a warm, tired, contented dog curled up at your side and a good Belgian ale in your chalice.

      Of course then too you could be very unlucky and be asked to process a symlink to a file on a different filesystem which just happens to have the same inode number . . . :)

      $ ls -i ./foo /tmp/foo 1808983 ./foo@ 228688 /tmp/foo $ perl -le 'print( (stat "./foo")[1] )' 228688

      So the truly paranoid might use join("|",(stat DATA)[0,1]).

      The original query did not specify what OS they were on.

      inode is meaningless on win32, so this suggestion is not portable.

      Sorry - I do not have a better original suggestion - I would settle for parsing $0 on win32.

      "When you are faced with a dilemma, might as well make dilemmanade. "

Re: Get My Own Name
by blue_cowdawg (Monsignor) on Feb 04, 2004 at 15:48 UTC

    Yep. At first blush if you use $0 that will give you the name of the script being executed. But be careful. Let me show you a few case studies.

    Invoking a script via the interpreter

    Consider the following very simple script:
    #!/usr/bin/perl -w print $0,"\n";
    If I invoke it as
    perl testzero.pl
    sure enough it prints testzero.pl to stdout. Let's add a wrinkle! If I execute it as perl /home/peter/testzero.pl then then entire path name will be printed to stdout.

    chmod'ed script

    If I do a chmod 755 testzero.pl on my hapless script (assuming *nix environment here) then I have a similar problem. Executing
    ./testzero.pl
    will yield ./testzero.pl to stdout and so forth.

    In summary, hes you can get the path name of the script being executed but make sure you understand all of the implications.


    Peter L. Berghold -- Unix Professional
    Peter at Berghold dot Net
       Dog trainer, dog agility exhibitor, brewer of fine Belgian style ales. Happiness is a warm, tired, contented dog curled up at your side and a good Belgian ale in your chalice.
      There is also the interesting ( althought not relevant to the OP ) case of doing:
      perl -e 'print "My name is $0.\n\n";'

      which produces: "My name is -e."

      --tidiness is the memory loss of environmental mnemonics

      If you need to figure out the current script, with path or not, FindBin.

      use FindBin; print $FindBin::Bin, $/;

      --
      [ e d @ h a l l e y . c c ]

Re: Get My Own Name
by EvdB (Deacon) on Feb 04, 2004 at 15:40 UTC
    From perldoc perlvar:
    $0 Contains the name of the program being executed. On some (read: not all) operating systems assigning to $0 modifies the argument area that the "ps" program sees. On some platforms you may have to use special "ps" options or a different "ps" to see the changes. Modifying the $0 is more useful as a way of indicating the current program state than it is for hiding the program you're running. (Mnemonic: same as sh and ksh.) Note that there are platform specific limitations on the the maximum length of $0. In the most extreme case it may be limited to the space occupied by the original $0. In some platforms there may be arbitrary amount of padding, for example space characters, after the modified name as shown by "ps". In some platforms this padding may extend all the way to the original length of the argument area, no matter what you do (this is the case for example with Linux 2.2). Note for BSD users: setting $0 does not completely remove "perl" from the ps(1) output. For example, setting $0 to "foobar" may result in "perl: foobar (perl)" (whether both the "perl: " prefix and the " (perl)" suffix are shown depends on your exact BSD variant and version). This is an operating system feature, Perl cannot help it. In multithreaded scripts Perl coordinates the threads so that any thread may modify its copy of the $0 and the change becomes visible to ps(1) (assuming the operating system plays along). Note that the the view of $0 the other threads have will not change since they have their own copies of it.

    --tidiness is the memory loss of environmental mnemonics

Re: Get My Own Name
by valdez (Monsignor) on Feb 04, 2004 at 15:41 UTC
    $0, please read also perlvar.

    Ciao, Valerio

Re: Get My Own Name
by flyingmoose (Priest) on Feb 04, 2004 at 19:32 UTC
    given $0 is unreliable and inode theory is not portable, I have to ask (please forgive me) -- just what are you trying to do?

    I understand the current problem, but what is the purpose of this script? It may be, for instance, that you can make better choices about what file is a potential target for processing (based on name or contents). You may be able to run this from another path.

    This problem seems sort of odd, so I think that warrants an inquiry into the function of the script.

      Because tar on HP-UX is broken, we have been forced to implement our own work around. Normally, on Solaris at least, you can supply tar with an exclude file. Thus allowing you to avoid tarring up mp3s or your collections of GTK+ themes and backgrounds or what have you.

      I wanted to include this functionality in the script because you never can tell when some one is going to pass the script along to a friend but not tell them how to use it properly. Nor did I want to have to hardcode the name of the script since file names can change.

        I trust you're going to use Archive::Tar?

        If you are going to substitute for a program where you would have used and exclude-file, why don't you just implement exclude-file functionality into your program? No need to know your program's name (just like tar wouldn't need to know its name).


        The PerlMonk tr/// Advocate
        HP-UX tar is broken? How about GNU tar? It has exclude options
        That's why God gave us cpio.

        Abigail

Re: Get My Own Name
by archangelq (Novice) on Feb 04, 2004 at 20:02 UTC
    My suggestion would be to use File::Basename on $0, as it turns out. Example:
    use File::Basename; my $scriptname = basename($0);
    Simple and to the point. Then just an
    unless(basename($file) eq $scriptname) { ... }
    in your testing loop, there you go.

      This assumes you are not going deeper into the tree than the current dir. In that case, you may want to use:

      use File::Basename; my ($scriptname, $scriptdir) = fileparse($0); while($file = shift(@files)){ my($name, $dir) = fileparse($file); unless($dir eq $scriptdir and $scriptname eq $name){ ... } }

      Note: This code is drawn from memory, and not directly tested. I really should take the lead of some of the monks and just put a disclaimer in my sig. OTOH, I did check the perl docs to be sure I hadn't typoed names, and sure enough, I had, so at least it's not typo-rific.