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

Hiya, Something very odd is going on here (Very probably as a result of my dodgy coding) :)

The script below is script designed to neatly convert all the avi/mp4/ogm files in a directory into MKVs.
#!/usr/bin/perl while(<*>) { $o = $_; s/\ /\¬/g; rename($o, $_); } foreach (<*.avi>) { $cmd = "mkvmerge $_ -o "; s/\.avi$/.mkv/; $cmd .= $_; print "$cmd\n"; system($cmd); } @filelist = glob("*.avi"); unlink @filelist; foreach (<*.ogm>) { $cmd = "mkvmerge $_ -o "; s/\.ogm$/.mkv/; $cmd .= $_; system($cmd); } @filelist = glob("*.ogm"); unlink @filelist; foreach (<*.mp4>) { $cmd = "mkvmerge $_ -o "; s/\.mp4$/.mkv/; $cmd .= $_; system($cmd); } @filelist = glob("*.mp4"); unlink @filelist; while(<*>) { $_ = $o; s/\ /\¬/g; rename($_, $o); } while(<*>) { $o = $_; s/\¬/\ /g; rename($o, $_); }
I've saved it in /usr/bin to give me systemwide capability. In essence, the script should run through a four step process-
1. Replace any spaces in filenames with the ¬ character.
2. Run MKV merge on the files that need it.
3. Delete the source files.
4. Put the spaces back into the filenames.


The problem is that it only works correctly as root. If I launch it as a normal user, it only works if a file with spaces in it's name is present. When there are no files with spaces, it simply skips on to the deletion phase.

Basically, I don't understand why when there are no filenames with spaces present it works correctly as root, but not as a normal user.

FWIW, I chose to write this in Perl, as this script occasionally gets used on my Windows machine. Here it works correctly too.

Cheers

Replies are listed 'Best First'.
Re: Why does this only work correctly as root?
by ig (Vicar) on Aug 06, 2009 at 12:07 UTC

    You can probably find out where and why your program is failing by adding error detection and reporting.

    Every time you perform a function that could fail, you should check to determine whether or not it failed and if it failed you should write an appropriate error message. For example, you could change your first two loops to be something like the following:

    while (<*>) { $o = $_; s/\ /\¬/g; rename( $o, $_ ) or die "rename $o to $_: $!"; } foreach (<*.avi>) { $cmd = "mkvmerge $_ -o "; s/\.avi$/.mkv/; $cmd .= $_; print "$cmd\n"; system($cmd) == 0 or die "$cmd: failed with status $?"; }

    Also, although it might make no difference here, I suggest you use strict and warnings, by adding the following near the top of your file:

    use strict; use warnings;

    See Use strict and warnings for more information on strict and warnings.

      Or even simpler: use autodie qw(system); Then you don't have to modify the rest of the source at all.
Re: Why does this only work correctly as root?
by jethro (Monsignor) on Aug 06, 2009 at 12:18 UTC

    When I tried your script (on linux as normal user), it worked.

    You should check if the system call was successful before you delete a source file

    Better would be to use opendir to get at the files (without the hackish renaming step) and do the "convert, check if successful, delete source" steps together for each file. Use escaping (i.e. put one or two \ before a space) or surround the filename with ' or " in the system call and it will work with spaces too.

Re: Why does this only work correctly as root?
by Anonymous Monk on Aug 06, 2009 at 15:39 UTC
    I've now discovered the cause of this- Brackets in the filenames (Arrgh- root was a red herring caused by my test file) I've added the suggested error checking and two more sets of rename statements to cope with these at present, which appears to be working. Do you have an example of using Opendir for this sort of thing? I managed to get it to run MKVMerge for every file, but I can't get it to play nice with the extensions. Cheers
      my $f; Opendir($f,"."); my $filename; while ($filename=readdir($f)) { if ($filename=~/\.avi$/) { $filename=~s/([ \[\];$'"()])/\\$1/g; #adds \ before spaces, bracke +ts and other special chars ... } }

      Note I do not know how escaping works in windows (where \ is dir separator) or what special chars make problems there. So above probably needs some more refinement to work on both platforms.