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

This may be amazingly easy to you guys, but I cannot understand why it is not working. Typically I use 'cd' to change to a directory I wish the command executed in and its fine. But, the following will always place an empty tgz file in the root directory and nothing goes to the backup directory. What I am tryin to do is create a backup script that will backup some directories that cannot get backed up with the normal ones that occur. It seems that simply the 'cd' is not working? It is being run as root so it should be able to go anywhere. I am pretty sure I have used 'cd' before with success. Another question I had was if the tarring processes would take a while would it cause problems? So, would it get to the 'mv' functions and so on before it completes the tarring thus causing problems? ...or does perl wait until each command is done before moving on? Any help would be great! Thanks
system ("cd /path/to/dirs"); system ("tar -czvf dir1.tgz dir1/"); system ("tar -czvf dir2.tgz dir2/"); system ("tar -czvf dir3.tgz dir3/"); system ("mv /path/to/dirs/dir1.tgz /backup/dir1.tgz"); system ("mv /path/to/dirs/dir2.tgz /backup/dir2.tgz"); system ("mv /path/to/dirs/dir3.tgz /backup/dir3.tgz");

Replies are listed 'Best First'.
Re: cd in perl not working?
by Corion (Patriarch) on Nov 26, 2008 at 20:52 UTC

    That's not how system() works. Or rather, see system. It spawns a shell, which executes the cd command and then exits, leaving your program's working directory completely unchanged. You want to use Cwd chdir.

    Also consider replacing shelling out to mv with rename.

    Replacing tar with Archive::Tar is possible, but Archive::Tar is limited by your available memory and likely is less compatible than your installed tar binary.

    Update: runrig is correct, chdir is what's needed, not getcwd from Cwd.

      you mean chdir. Cwd gives you the Current Working Directory.
Re: cd in perl not working?
by oko1 (Deacon) on Nov 27, 2008 at 00:04 UTC

    It's been noted that "system" doesn't work the way you think it does; you're spawning a child shell, changing directory within that shell, then exiting it. Then, you spawn another shell and execute "tar" within it, and so on.

    In general, you want to stick with Perl functions instead of shelling out (as Corion noted), but if you want to do all of the above, you might consider using a heredoc:

    # NOTE: Those are backticks, not single quotes, around the delimiter print <<`ShellOut`; cd /path/to/dirs tar -czvf dir1.tgz dir1/ tar -czvf dir2.tgz dir2/ tar -czvf dir3.tgz dir3/ mv /path/to/dirs/dir1.tgz /backup/dir1.tgz mv /path/to/dirs/dir2.tgz /backup/dir2.tgz mv /path/to/dirs/dir3.tgz /backup/dir3.tgz ShellOut

    This should do what you want.


    --
    "Language shapes the way we think, and determines what we can think about."
    -- B. L. Whorf
Re: cd in perl not working?
by jeffa (Bishop) on Nov 26, 2008 at 20:57 UTC

    Perl waits for each command to finish -- i believe that involves spawning a new process and waiting on it, collecting the results. Which, by the way, you should be reporting on. Can you provide the error message? This will help us to understand what the real problem is.

    Also, if this is all that this script does (and you are in a Unix like environment) then you should use a shell to execute this stuff, like bash:

    cd /path/to/dirs tar -czvf dir1.tgz dir1/ ... mv /path/to/dirs/dir1.tgz /backup/dir1.tgz ...

    Finally, Perl has File::Copy and other modules for archiving files as well as a built in mv named rename -- so if you are going to keep this in Perl you might want to use those and eliminate some overhead that system brings.

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)
    
Re: cd in perl not working?
by metal_cd (Initiate) on Nov 27, 2008 at 02:40 UTC
    You guys are geniuses, what you all said was true and accurate. I experimented some more and found it just wasn't stickin with the use of 'system (cd...)'. By the way the errors I was receiving were alot of the 'cannot stat... no such directory' due to it not switching for me. It wasn't till the use of the `ShellOut` as provided by oko1(way to go!) that it stayed put. I just grouped everything needed to be executed in a particular directory(what I provided above was just a brief example) and it works fantastic. Some of the files are well over a gig and its working fine. It will be cycling and providing daily, weekly, bi-weekly, monthly, and bi-monthly backup retention. This is way cool. Thanks again guys, you rock!
      Amen. Years later and this is still a very useful post. I don't know what the difference is, but this method: print <<`ShellOut`; ... ShellOut was the only way I could get this to work. Never had a problem before, but I just set up a new CentOS machine, tried to run some shell commands using "system" or just backticks, and it would not work. The lack of a persistent session issue is duly noted -- that was ONE of my issues, but even once I realized that a "cd" in one "system" command did not apply to the next "system" command, it would not work correctly. Again, I don't know why the above method does work when the others do not, but I am not going to dwell on it - I just wanted it to work. Thank you.

        Old thread, yes. But you got me thinking too. In the spirit of TMTOWTDI I offer an alternative: Put the commands in one system() call, separated by semicolons. Works for me using Perl 5.18.2 in Ubuntu 14.04 with Bash as default shell. Instead of tarring files I ran "ls -ao" after changing directories, as in the example below.

        system("cd ~/jobs; ls -ao; cd ..");