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

I have a command (cdrecord on Linux) that I need to get the output from. I can run the command using the backticks, but the command completes before the output gets back to me. I am needing to get the percentage of the CD cut before it completes. Does anyone know how I could do this?
  • Comment on not waiting for external command to complete before getting the output

Replies are listed 'Best First'.
Re: not waiting for external command to complete before getting the output
by Joost (Canon) on Apr 26, 2004 at 13:46 UTC
      cdrecord seems to be buffering output
      Thanks guys. Been away making supper. Now, Seems like this silly cdrecord thing is buffering the output. I tried what was suggested and noting was output until the enture cd had completed the record (which of course by that stage is way too late). So, now the question is: how do I get hold of this output without hacking cdrecord?
      perl -e 'open (FD1, "/usr/bin/cdrecord -vs -dummy -eject /mnt/test/Deb +ian/2disc.iso |"); while (<FD1>) { $_ =~ s/^M//g; print $_ if /^Track/; }; close (FD1)
      My output looks like:
      Track 01: 0 of 47 MB written.Track 01: 1 of 47 MB written (fifo 96%).....etc.

      Thanks for the help so far.
      Cheers
      H
Re: not waiting for external command to complete before getting the output
by muntfish (Chaplain) on Apr 26, 2004 at 13:51 UTC

    I'm not familiar with cdrecord, but assuming it prints stuff to standard output while it is progressing, you could pipe its output into perl like this:

    print "invoking cdrecord...\n"; open CD, "cdrecord |" or die "Couldn't run cdrecord"; while(<CD>) { # check $_ for whatever output you're looking for # or just print $_; } close CD; print "cdrecord finished\n";

    I hope that's useful. If you can supply a bit more info about how cdrecord outputs its progress, that may help get a more precise answer.

Re: not waiting for external command to complete before getting the output
by mutated (Monk) on Apr 26, 2004 at 13:55 UTC
    I suggest use Expect; it's great for interactive sessions with anything. Documentation is a bit sparse, but it's worth taking the time to learn.


    daN.
Re: not waiting for external command to complete before getting the output
by zentara (Cardinal) on Apr 28, 2004 at 17:42 UTC
    Ok, here you go, this works, tested on linux. It uses sysread to get the output, and it gets around the \r problem.
    #!/usr/bin/perl use warnings; use IPC::Open3; #cdrecord sends a /r (no newline) to output status #so it is difficult to get output my $pid = open3(\*WRITE, \*READ,0,"/usr/bin/cdrecord -v -dummy -eject +dev=1,1,0 my.iso"); #if \*ERROR is false, STDERR is sent to STDOUT while(1){ select(undef,undef,undef,.01); if( sysread \*READ,$output,1024 ){ print "$output\n"; }else{ print "finished\n"; exit; } }
    OUTPUT from my testing:
    Track 01: 89 of 97 MB written (fifo 100%) [buf 99%] 27.3x. Track 01: 90 of 97 MB written (fifo 100%) [buf 99%] 26.5x. Track 01: 91 of 97 MB written (fifo 98%) [buf 99%] 27.3x. Track 01: 92 of 97 MB written (fifo 100%) [buf 99%] 26.6x. Track 01: 93 of 97 MB written (fifo 98%) [buf 99%] 27.4x. Track 01: 94 of 97 MB written (fifo 100%) [buf 99%] 26.6x. Track 01: 95 of 97 MB written (fifo 100%) [buf 99%] 27.4x. Track 01: 96 of 97 MB written (fifo 100%) [buf 99%] 28.3x. Track 01: 97 of 97 MB written (fifo 100%) [buf 99%] 27.5x. Track 01: Total bytes read/written: 102400000/102400000 (50000 sectors +). Writing time: 42.959s Average write speed 15.5x. Min drive buffer fill was 99% Fixating... WARNING: Some drives don't like fixation in dummy mode. Fixating time: 26.760s /usr/bin/cdrecord: fifo had 1613 puts and 1613 gets. /usr/bin/cdrecord: fifo was 0 times empty and 872 times full, min fill + was 85%. finished

    I'm not really a human, but I play one on earth. flash japh
Re: not waiting for external command to complete before getting the output
by zentara (Cardinal) on Apr 27, 2004 at 11:47 UTC
    As an alternative to expect, here is a basic setup for IPC::Open3. You should be able to get the error thrown by cdrecord when you run this. Just put the reads in a while(1) loop, and check for your percentage done.
    #!/usr/bin/perl use warnings; use strict; use IPC::Open3; my $pid = open3(\*WRITE, \*READ,0,"/usr/bin/cdrecord -v -dummy -eject +/mnt/my.iso"); #if \*ERROR is false, STDERR is sent to STDOUT #while(1){ #select(undef,undef,undef,.01); chomp(my $output = <READ>); print "$output\n"; #do some split and test to extract percentage #} waitpid($pid, 1); # It is important to waitpid on your child process, # otherwise zombies could be created.

    I'm not really a human, but I play one on earth. flash japh
      Thanks guys for the help.

      I have tried all these solutions. None of them work. They all print the information I am wanting at the end of cutting the CD. I looked through the cdrecord code, and Jorg places a \r at the beginning of each line of output denoting how much of the cd has been cut. I tried removing those in perl, but to no avail either.
      What's really strange is if I redirect the output to a file, and then tail the file simultaneously, I get the information I am after. When I look at the file with VI, I see the following type of output:

      ^MTrack 01 0 of 47MB^MTrack 01 1 of 47MB^MTrack 01 2 of 47MB^M.....etc....

      This has the effect that each line indicating the percent of the track cut is over-written by the next line, creating that "nice" feeling of interactivity. I just find it's making my life hell.

      Also not sure that I fully understand how it can well be appending to a file on redirecting output from cdrecord, but not giving me the output when I pop the same in a perl script.
      Cheerio
      Hambo
        There is some information on dealing with these situations in "perldoc -q filehandle", about using sysread and ioctl. I'll try to get an example that works with cdrecord and post it later.

        I'm not really a human, but I play one on earth. flash japh