Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

Can I stop a backtick command but continue the script?

by DentArthurDent (Monk)
on Mar 02, 2005 at 17:53 UTC ( #435947=perlquestion: print w/ replies, xml ) Need Help??
DentArthurDent has asked for the wisdom of the Perl Monks concerning the following question:

Suppose I'm running a backticks or system command through a script that I've run from the command line. Is there anyway for me to stop that command midstream and have the script continue?

The application in question is a very simple MP3 shuffle player. What I want to be able to do is go to the next song while the current one is playing. Read more for the code.

#!/usr/bin/perl use Data::Dumper; open(PLAYLIST,"</somedir/myplaylist.lst"); my @songs; while (<PLAYLIST>) { chomp(); push(@songs,$_); } my $count = scalar(@songs); print "We found $count songs\n"; while (scalar(@songs) > 0) { my $song_num = rand(scalar(@songs)); print "*** Playing $songs[$song_num]\n"; `mpg321 '$songs[$song_num]'`; splice(@songs,$song_num,1); }
If it makes any difference, this is Perl 5.8.5 on SuSE Linux 9.2.

UPDATE: After taking my first steps into the larger world of fork/exec, I have something that works to the best that I can see. Read on for the new version. I'll probably eventually update it to not use ^C to get the next song so it's easier to stop the music. Thanks to RazorbladeBidet for gently pushing me to learn fork!
#!/usr/bin/perl my $song_num; my @songs; my $pid; sub catch_next { my $signame = shift; print "Going to next song!\n"; my $count = kill(15,$pid); } sub reaper { $waitedpid = wait; $SIG{CHLD} = \&reaper; } open(PLAYLIST,"</somedir/myplaylist.lst"); while (<PLAYLIST>) { chomp(); push(@songs,$_); } $SIG{INT} = \&catch_next; $SIG{CHLD} = \&reaper; my $count = scalar(@songs); print "We found $count songs\n"; while (scalar(@songs) > 0) { $song_num = rand(scalar(@songs)); my $song = $songs[$song_num]; splice(@songs,$song_num,1); print "*** Playing $song\n"; unless ($pid = fork) { exec("mpg321", "$song"); } waitpid($pid,0); }
UPDATE 2: Thanks to bluto for alerting me that I don't need a seperate SIGCHLD handler. The final code is below:
#!/usr/bin/perl my $song_num; my @songs; my $pid; sub catch_next { my $signame = shift; print "Going to next song!\n"; my $count = kill(15,$pid); } open(PLAYLIST,"</somedir/myplaylist.lst"); while (<PLAYLIST>) { chomp(); push(@songs,$_); } $SIG{INT} = \&catch_next; my $count = scalar(@songs); print "We found $count songs\n"; while (scalar(@songs) > 0) { $song_num = rand(scalar(@songs)); my $song = $songs[$song_num]; splice(@songs,$song_num,1); print "*** Playing $song\n"; unless ($pid = fork) { exec("mpg321", "$song"); } waitpid($pid,0); }

Comment on Can I stop a backtick command but continue the script?
Select or Download Code
Re: Can I stop a backtick command but continue the script?
by RazorbladeBidet (Friar) on Mar 02, 2005 at 17:59 UTC
    If you hit CTRL^C during playback, what happens?

    My first thought is that if CTRL^C doesn't work (or exits the whole program) - you would want to handle the signal. See Signals.

    If you want another option, you may want to fork and exec a child, then wait and listen for a certain key to kill the child.

    Just a couple of thoughts, I'm sure there are many many others.
    --------------
    It's sad that a family can be torn apart by such a such a simple thing as a pack of wild dogs
Re: Can I stop a backtick command but continue the script?
by dmorelli (Scribe) on Mar 02, 2005 at 18:11 UTC
    If you don't need to grab the output of the program (which is one reason to be using backticks in the first place), you could use system() instead:

    system "mpg321 $songs[$song_num]";

Re: Can I stop a backtick command but continue the script?
by bluto (Curate) on Mar 02, 2005 at 21:08 UTC
    Regarding your updated code: Since the parent is doing a waitpid(), you do not want to set up a SIGCHLD handler. Use either one or the other (I'd suggest the waitpid). If the waitpid reaps the child, the SIGCHLD wait call will hang waiting for yet another child to be reaped.
      That comes from not knowing what one is doing and copying code from several other places at once. Thanks for the tip!
      ----
      My mission: To boldy split infinitives that have never been split before!
Re: Can I stop a backtick command but continue the script?
by saintmike (Vicar) on Mar 02, 2005 at 23:01 UTC
    Controlling an external player is tricky ... check out how this perl application does it.
Re: Can I stop a backtick command but continue the script?
by tphyahoo (Vicar) on Mar 03, 2005 at 11:06 UTC
    I'm a thread newbie on Windows/ActiveState and am just trying to figure out how to approach this whole mess, trying to glean knowledge from the masters.

    Perlthrtut says fork is dangerous, use threads.

    I think this is controversial. I also think this has been discussed before.

    Can someone point me to where I can decide whether to do my multithreaded stuff using fork or thread, in a windows context?

    UPDATE: Search on fork thread brings some good results, I know I know, but maybe *too* much. If someone could just tell me what to read based on personal experience I'd be grateful. Or maybe I'll just do a "survey of fork versus thread" like I did for the morass of perl html templating systems a few days ago...

    This merlyn post seems pretty good forking paralell link checker...

Re: Can I stop a backtick command but continue the script?
by zentara (Archbishop) on Mar 03, 2005 at 12:32 UTC
    I played around with that before, but used Tk which has "an event loop" to make this sort of thing easier. POE might be able to help you on the command-line versions. In the sources for mpg123, there is a README.remote file, which describes how to remotely control the player. You will have to play your songs thru the "piped-form of open", rather than backticks, so you can signal the player to skip to the next songs. With bacticks, killing the song, will kill the instance of the player, so you will be creating a new player for each song....kind of wasteful. The following example, has a "Pause" Button, but you can skip to the next song in a playlist by just LOADING it.
    #!/usr/bin/perl use warnings; use strict; use Tk; #read README.remote in mpg123 sources $|++; #my $pid = open(FH,"| mpg123 -R 2>&1 "); my $pid = open(FH,"| mpg123 -R >/dev/null 2>&1 "); print "$pid\n"; my $mw = new MainWindow; my $startbut = $mw->Button(-text =>'Start Play', -command => sub{ syswrite(FH, "LOAD 1bb.mp3\n") ; })->pack; my $pausebut = $mw->Button(-text =>'Pause', -command => sub{ syswrite(FH, "PAUSE\n") ; })->pack; my $exitbut = $mw->Button(-text =>'Exit', -command => sub{ exit })->pack; MainLoop;

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

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://435947]
Approved by Joost
Front-paged by husker
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (5)
As of 2014-09-18 02:20 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    How do you remember the number of days in each month?











    Results (104 votes), past polls