Piping two shell commands together

Discussion in 'Ruby' started by Hans Fugal, Aug 2, 2007.

  1. Hans Fugal

    Hans Fugal Guest

    I want to pipe two system commands together from within ruby. cmd1 and
    cmd2 are arrays, e.g.

    cmd1 = ['oggdec','-o','-',oldpath]
    cmd2 = ['lame','-',newpath]

    I think I can do the following,

    IO.popen('-','r') do |p1|
    exec cmd1 unless p1
    IO.popen('-','w') do |p2|
    exec cmd2 unless p2
    p2.write(p1.read)
    end
    end

    but I don't like the line "p2.write(p1.read)", because I think it will
    read into memory from p1 before turning around and writing it to p2.
    This may work for the above example, but it's not very pipelike and I
    worry that read might return early (I'm not sure what the semantics of
    that are in Ruby, but in C I'd have to account for that).

    Plus I don't like the popen '-'/exec combination. I'd love a more
    elgant, efficient, and/or safer idiom if anyone can think of one.
     
    Hans Fugal, Aug 2, 2007
    #1
    1. Advertising

  2. Hans Fugal

    matt neuburg Guest

    Hans Fugal <> wrote:

    > I want to pipe two system commands together from within ruby. cmd1 and
    > cmd2 are arrays, e.g.
    >
    > cmd1 = ['oggdec','-o','-',oldpath]
    > cmd2 = ['lame','-',newpath]


    I don't know about the arrays, but you can say IO.popen ("oggdec |
    lame").... m.

    --
    matt neuburg, phd = , http://www.tidbits.com/matt/
    Tiger - http://www.takecontrolbooks.com/tiger-customizing.html
    AppleScript - http://www.amazon.com/gp/product/0596102119
    Read TidBITS! It's free and smart. http://www.tidbits.com
     
    matt neuburg, Aug 2, 2007
    #2
    1. Advertising

  3. Hans Fugal

    Hans Fugal Guest

    matt neuburg wrote:
    > Hans Fugal <> wrote:
    >
    >> I want to pipe two system commands together from within ruby. cmd1 and
    >> cmd2 are arrays, e.g.
    >>
    >> cmd1 = ['oggdec','-o','-',oldpath]
    >> cmd2 = ['lame','-',newpath]

    >
    > I don't know about the arrays, but you can say IO.popen ("oggdec |
    > lame").... m.
    >


    Yeah, that won't work here (unless there's a reliable way to
    shell-quote/escape oldpath and newpath).
     
    Hans Fugal, Aug 2, 2007
    #3
  4. Hans Fugal

    matt neuburg Guest

    Hans Fugal <> wrote:

    > matt neuburg wrote:
    > > Hans Fugal <> wrote:
    > >
    > >> I want to pipe two system commands together from within ruby. cmd1 and
    > >> cmd2 are arrays, e.g.
    > >>
    > >> cmd1 = ['oggdec','-o','-',oldpath]
    > >> cmd2 = ['lame','-',newpath]

    > >
    > > I don't know about the arrays, but you can say IO.popen ("oggdec |
    > > lame").... m.
    > >

    >
    > Yeah, that won't work here (unless there's a reliable way to
    > shell-quote/escape oldpath and newpath).


    I'm a little confused about oldPath. Once you have told IO.popen to
    generate an IO instance (let's call it ios), whatever you write to ios
    passes thru the process. So you don't actually need to tell IO.popen
    about oldpath; you just write the data.

    As for quoting, I just put quotes around it.

    So, for example, a way to do LAME encoding with Ruby is like this:

    oldpath = "/Users/mattneub/some sound file.aif"
    newpath = "/Users/mattneub/some sound file.mp3"
    s = "lame --preset standard - '#{newpath}'"
    IO.popen(s, "r+") do |ios|
    ios.write(File.read(oldpath))
    end

    So maybe you could say:

    s = "oggdec -R -o - - | lame ... - '#{newpath}'"

    I've suggested -R because the oggdec man page warns not to write WAV to
    stdout. But then I've omitted some lame params (...) because you'll
    probably need to tell lame what kind of raw data it's receiving. I
    haven't tried this, though.

    m.

    --
    matt neuburg, phd = , http://www.tidbits.com/matt/
    Tiger - http://www.takecontrolbooks.com/tiger-customizing.html
    AppleScript - http://www.amazon.com/gp/product/0596102119
    Read TidBITS! It's free and smart. http://www.tidbits.com
     
    matt neuburg, Aug 2, 2007
    #4
  5. Hans Fugal

    ara.t.howard Guest

    On Aug 2, 2007, at 10:40 AM, Hans Fugal wrote:

    > cmd1 = ['oggdec','-o','-',oldpath]
    > cmd2 = ['lame','-',newpath]
    >
    > I think I can do the following,
    >
    > IO.popen('-','r') do |p1|
    > exec cmd1 unless p1
    > IO.popen('-','w') do |p2|
    > exec cmd2 unless p2
    > p2.write(p1.read)
    > end
    > end
    >


    an alternative:

    cfp:~ > ruby a.rb
    1073741824
    1073741824



    cfp:~ > cat a.rb
    require 'open4'

    cmd1 = 'ruby -e" (2 ** 10).times{ STDOUT.write 0.chr * 2**20 } "'
    cmd2 = 'ruby -e" puts ARGF.read.size "'

    stdin = IO.popen cmd1

    stdout, stderr = '', ''

    status = Open4.spawn cmd2, 0=>stdin, 1=>stdout, 2=>stderr

    puts stdout
    puts 2 ** 30



    a @ http://drawohara.com/
    --
    we can deny everything, except that we have the possibility of being
    better. simply reflect on that.
    h.h. the 14th dalai lama
     
    ara.t.howard, Aug 2, 2007
    #5
  6. Hans Fugal

    matt neuburg Guest

    matt neuburg <> wrote:

    > So, for example, a way to do LAME encoding with Ruby is like this:
    >
    > oldpath = "/Users/mattneub/some sound file.aif"
    > newpath = "/Users/mattneub/some sound file.mp3"
    > s = "lame --preset standard - '#{newpath}'"
    > IO.popen(s, "r+") do |ios|
    > ios.write(File.read(oldpath))
    > end
    >
    > So maybe you could say:
    >
    > s = "oggdec -R -o - - | lame ... - '#{newpath}'"
    >
    > I've suggested -R because the oggdec man page warns not to write WAV to
    > stdout. But then I've omitted some lame params (...) because you'll
    > probably need to tell lame what kind of raw data it's receiving. I
    > haven't tried this, though.


    Yes, I just tried it. (Had to download and compile and install the ogg
    stuff first.) I started with a mono aiff file; then I ogg'ed using the
    default setting. Then I said:

    oldpath = "/Users/mattneub/some sound file.ogg"
    newpath = "/Users/mattneub/some sound file.mp3"
    s = "oggdec -R -o - - | lame -r -x -m m --preset standard -
    '#{newpath}'"
    IO.popen(s, "r+") do |ios|
    ios.write(File.read(oldpath))
    end

    Worked great. If your file isn't mono, leave out the "-m m". If your
    native endianity does not require it, leave out the "-x". Looks pretty
    "pipey" to me!

    m.

    --
    matt neuburg, phd = , http://www.tidbits.com/matt/
    Tiger - http://www.takecontrolbooks.com/tiger-customizing.html
    AppleScript - http://www.amazon.com/gp/product/0596102119
    Read TidBITS! It's free and smart. http://www.tidbits.com
     
    matt neuburg, Aug 3, 2007
    #6
  7. Hi,

    At Fri, 3 Aug 2007 01:40:00 +0900,
    Hans Fugal wrote in [ruby-talk:263040]:
    > I want to pipe two system commands together from within ruby. cmd1 and
    > cmd2 are arrays, e.g.
    >
    > cmd1 = ['oggdec','-o','-',oldpath]
    > cmd2 = ['lame','-',newpath]


    IO.popen('-','r') do |p1|
    exec(*cmd1) unless p1
    IO.popen('-','w') do |p2|
    unless p2
    STDIN.reopen(p1)
    exec(*cmd2)
    end
    end
    end

    --
    Nobu Nakada
     
    Nobuyoshi Nakada, Aug 3, 2007
    #7
  8. Hans Fugal

    Hans Fugal Guest

    matt neuburg wrote:
    > Hans Fugal <> wrote:
    >
    >> matt neuburg wrote:
    >>> Hans Fugal <> wrote:
    >>>
    >>>> I want to pipe two system commands together from within ruby. cmd1 and
    >>>> cmd2 are arrays, e.g.
    >>>>
    >>>> cmd1 = ['oggdec','-o','-',oldpath]
    >>>> cmd2 = ['lame','-',newpath]
    >>> I don't know about the arrays, but you can say IO.popen ("oggdec |
    >>> lame").... m.
    >>>

    >> Yeah, that won't work here (unless there's a reliable way to
    >> shell-quote/escape oldpath and newpath).

    >
    > I'm a little confused about oldPath. Once you have told IO.popen to
    > generate an IO instance (let's call it ios), whatever you write to ios
    > passes thru the process. So you don't actually need to tell IO.popen
    > about oldpath; you just write the data.
    >
    > As for quoting, I just put quotes around it.
    >
    > So, for example, a way to do LAME encoding with Ruby is like this:
    >
    > oldpath = "/Users/mattneub/some sound file.aif"
    > newpath = "/Users/mattneub/some sound file.mp3"
    > s = "lame --preset standard - '#{newpath}'"
    > IO.popen(s, "r+") do |ios|
    > ios.write(File.read(oldpath))
    > end
    >
    > So maybe you could say:
    >
    > s = "oggdec -R -o - - | lame ... - '#{newpath}'"
    >
    > I've suggested -R because the oggdec man page warns not to write WAV to
    > stdout. But then I've omitted some lame params (...) because you'll
    > probably need to tell lame what kind of raw data it's receiving. I
    > haven't tried this, though.


    What happens when you try to encode to newpath = "Beethoven's 5th" or
    something with an apostrophe?

    I did come up with a working solution, which you can read about here:
    http://hans.fugal.net/blog/articles/2007/08/02/pipelining-processes-in-ruby

    Cheers
     
    Hans Fugal, Aug 4, 2007
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Allan Rojas

    Shell commands in ASP.NET?

    Allan Rojas, Jul 3, 2003, in forum: ASP .Net
    Replies:
    3
    Views:
    3,769
    dave wanta
    Jul 3, 2003
  2. Ben Pfaff

    Re: man pages for C commands (GCC commands)

    Ben Pfaff, Jun 24, 2003, in forum: C Programming
    Replies:
    4
    Views:
    4,009
    Thomas Stegen
    Jun 28, 2003
  3. Tim Stanka
    Replies:
    1
    Views:
    836
    Jeff Epler
    Aug 2, 2004
  4. Replies:
    1
    Views:
    290
    Simon Forman
    Jul 18, 2006
  5. Luca Cerone
    Replies:
    13
    Views:
    154
    Tobiah
    Aug 5, 2013
Loading...

Share This Page