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

Here's the situation, I have an executable that gets info about a database (I didn't write it). When run from the shell it prints out a dozen lines describing database. Example:

Version
Release date:
Creation date: 2:17:09 AM EST Nov 19, 2004
Modified date: 2:17:09 AM EST Nov 19, 2004
Type: Nucleotide
Alphabet: NCBI2na(1)
No. of sequences (letters): 37,316 (33,115,935)
Longest sequence: 1542
Edit Alphabet: WUStLna(1)
Max. edits: 41
Total edits: 2693

I want a line in the middle that gives sequence count (in this example 37,316). I can gather the output with backticks and extract this number with some regular expression acrobatics, and store it in a variable easy enough. The problem is that everytime I execute the database info command, its output is automatically printed to the screen.

I don't want to see this output, I just want to run the script, have it gather the other program's output behind the scenes, and print out just the number. Is this even possible? I have tried a variety of ways of running the external program such as backticks, opening a pipe and using exec(), doing a manual fork() then exec(), and plain old system(). They all seem to work the same. Do I need to somehow filter my own STDOUT?

Thanks,
Jared

  • Comment on capture STDOUT without printing to screen

Replies are listed 'Best First'.
Re: capture STDOUT without printing to screen
by bart (Canon) on Dec 01, 2004 at 15:53 UTC
    Backticks (AKA qx) capture all of STDOUT. Nothing will ever make it to the screen.

    My guess is that your info is actually sent to STDERR. Try redirecting that to /dev/null in the command line. (nul on PC)

      If you are running a *NIX, you may be able to do this:

      my @lines_of_output = `sh /path/to/binary 2>&1`;

      You may not even need the 'sh' if your default shell supports the same redirection syntax. The '2>&1' tells the shell (which will execute your binary) to redirect all output on STDERR to STDOUT. STDOUT stuff will be left alone.

      So, unless your external program is doing something odd like opening /dev/console or /dev/tty or something, the above should get you exactly what you'd otherwise see on the screen.


      radiantmatrix
      require General::Disclaimer;
      Perl is

Re: capture STDOUT without printing to screen
by jfroebe (Parson) on Dec 01, 2004 at 15:58 UTC

    Hi Jared

    My bet is that the program isn't writing to standard out else it wouldn't be printing to the screen when you run "myprog > somefile". It is more likely printing to STDERR.

    Jason L. Froebe

    update: I see Bart can type faster than I can :-)

    Team Sybase member

    No one has seen what you have seen, and until that happens, we're all going to think that you're nuts. - Jack O'Neil, Stargate SG-1

Re: capture STDOUT without printing to screen
by Fletch (Bishop) on Dec 01, 2004 at 17:02 UTC

    It's also possible, although highly unlikely, that it's opening /dev/tty and writing to that rather than either of STD{OUT,ERR} (Presuming of course an *NIX system). In that case you'd have to use something like Expect or IPC::Run.

Re: capture STDOUT without printing to screen
by hmerrill (Friar) on Dec 01, 2004 at 15:56 UTC
    I can't see why backticks won't work:
    my @output_lines_array = `/path/to/your_executable`; foreach my $line (@output_lines_array) { if (/^No. of sequences \(letters\): ([\d,])\s/) { print "No. of sequences = $1\n"; } }
    I'm a little out of practice so beware, but hopefully it's close.

      I am using Mac OS X so it is unix. Here's my full code.

      #!/usr/bin/perl -w if (@ARGV==0) { die "Usage: countseq.pl <dbname>\n"; } my $prog = "/usr/ncbi/blast2/xdformat -n -i $ARGV[0]"; my $strOutput; my @output = `$prog`; foreach my $line (@output) { if (/^No. of sequences \(letters\): ([\d,])\s/) { $strOutput = $1; } } die "No output gathered \n" unless defined($strOutput); print $strOutput;

      So from the shell here's what I get.

      myshell$ ./countseq.pl human
      Version
      Release date:
      Creation date: 2:17:09 AM EST Nov 19, 2004
      Modified date: 2:17:09 AM EST Nov 19, 2004
      Type: Nucleotide
      Alphabet: NCBI2na(1)
      No. of sequences (letters): 37,316 (33,115,935)
      Longest sequence: 1542
      Edit Alphabet: WUStLna(1)
      Max. edits: 41
      Total edits: 2693
      37316
      myshell$

      I just want to see the number on the bottom (37316) Any thoughts? Any idea on how to determine if xdformat is printing to anything other than STDOUT?
      Thanks, Jared

        As 'jfroebe' said below, xpdformat is probably also writing to STDERR (which is *NOT* captured by backticks). Read about STDERR by doing
        perldoc -q STDERR
        at a command prompt. The perldoc '-q' says to search the perldoc documentation for string "STDERR". Here's a snippet from that:
        Found in C:\Perl\lib\pod\perlfaq8.pod How can I capture STDERR from an external command? There are three basic ways of running external commands: system $cmd; # using system() $output = `$cmd`; # using backticks (``) open (PIPE, "cmd |"); # using open() With system(), both STDOUT and STDERR will go the same place as th +e script's STDOUT and STDERR, unless the system() command redirects +them. Backticks and open() read only the STDOUT of your command. Here's another snippet: ----------------------- You can also use file-descriptor redirection to make STDERR a dupl +icate of STDOUT: $output = `$cmd 2>&1`; open (PIPE, "cmd 2>&1 |"); And another snippet: -------------------- ...To capture a command's STDERR and STDOUT together: $output = `cmd 2>&1`; # either with backticks $pid = open(PH, "cmd 2>&1 |"); # or with an open pipe while (<PH>) { } # plus a read
        Anyway, hope that helps.