Find the answer to your Linux question:
Page 1 of 2 1 2 LastLast
Results 1 to 10 of 16
First of all, a disclaimer: I'm not a Linux programmer or guru. While I use the command line a little, and can write a simple shell script, I'm no expert ...
Enjoy an ad free experience by logging in. Not a member yet? Register.
  1. #1
    Just Joined!
    Join Date
    Jun 2008
    Posts
    3

    Stopping a Shell Script Command


    First of all, a disclaimer: I'm not a Linux programmer or guru. While I use the command line a little, and can write a simple shell script, I'm no expert in either.

    I need to automate (i. e., unattended start and stop) the following shell script:

    Code:
    #!/bin/sh
    cat /dev/video0 > /data/capture/$1
    The above script, when run directly, does exactly what I want, with no unnecessary overhead. I can start it with a cron job if I want, but how do I stop it at a particular time of day, or after a specific elapsed time?

    I've wracked my brain (and done a fair amount of Googling) trying to come up with a solution, and come up empty. Anybody have any helpful suggestions?

  2. #2
    Linux Engineer Freston's Avatar
    Join Date
    Mar 2007
    Location
    The Netherlands
    Posts
    1,049
    Welcome Prototerm!

    The easiest this is perhaps to schedule a kill.

    Just killall name_of_process at certain times or at certain intervals.
    Can't tell an OS by it's GUI

  3. #3
    Linux User
    Join Date
    Jun 2007
    Posts
    318
    If you can use an elapsed time then you can do it in one script by running the command in the background (by putting an & at the end of the command) and then waiting that amount of time.

    Code:
    #!/bin/sh
    cat /dev/video0 > /data/capture/$1 &
    _pid="`jobs -l | awk '{print $2}'`"
    sleep <no. of seconds>
    kill -TERM $_pid
    The 'jobs' command returns the PID of the background process.

  4. #4
    Linux Guru
    Join Date
    Nov 2007
    Location
    Córdoba (Spain)
    Posts
    1,513
    Quote Originally Posted by vsemaska View Post
    If you can use an elapsed time then you can do it in one script by running the command in the background (by putting an & at the end of the command) and then waiting that amount of time.

    Code:
    #!/bin/sh
    cat /dev/video0 > /data/capture/$1 &
    _pid="`jobs -l | awk '{print $2}'`"
    sleep <no. of seconds>
    kill -TERM $_pid
    The 'jobs' command returns the PID of the background process.
    In bash you could capture the pid like this:

    Code:
    #!/bin/bash
    cat /dev/video0 > /data/capture/$1 &
    _pid=$!
    sleep <no. of seconds>
    kill -TERM $_pid
    I don't have a copy of the genuine sh at hand, but I think $! is a bashism, so, you can only use that if you actually are using bash (in most linux distros /bin/sh is a link to bash, actually). You can check that with ls -l /bin/bash

    If portability is an issue or you run this in different OSes (i.e. bsd, solaris, linux...) then it would be a good idea not to use bash specific stuff. But I just leave the code there in case it's of some use to you.

    I disregard the usage of killall as much as I can, unless you are sure you are not actually going to regret it. It can be something quick (no need to check for a pid) on certain circumstances (when working in command line). But in a script there's absolutely no excuse to use killall in this situation. After all, you only have to code it once, and you will be using it probably thousands.

  5. #5
    Linux Engineer khafa's Avatar
    Join Date
    Apr 2008
    Location
    Tokyo, Japan
    Posts
    858
    hi,

    these are some subtilities to watch for here.
    1) vsemaska's solution
    this does not work if there are more than one process running background. its easy to correct this as you can use grep for example to make sure that you will get one and only one PID , that PID being what you are looking for.

    2) i92guboj's solution
    this is less likely to happen but if between
    Code:
    cat /dev/video0 > /data/capture/$1 &
    and
    Code:
    _pid=$!
    another underground process is created you will kill that process instead of the one you wanted to kill as $! returns the PID of the last background process.

    i pointed this out because kill is used here.
    Linux and me it's a love story

  6. #6
    Linux Guru
    Join Date
    Nov 2007
    Location
    Córdoba (Spain)
    Posts
    1,513
    Quote Originally Posted by khafa View Post
    hi,

    these are some subtilities to watch for here.
    1) vsemaska's solution
    this does not work if there are more than one process running background. its easy to correct this as you can use grep for example to make sure that you will get one and only one PID , that PID being what you are looking for.
    Well. To do so, you would need to know the pid to grep for it. And if you knew the pid in first place, then you would just use kill, and you wouldn't need all that magic. If that's not what you meant, then I missunderstood something.

    2) i92guboj's solution
    this is less likely to happen but if between
    Code:
    cat /dev/video0 > /data/capture/$1 &
    and
    Code:
    _pid=$!
    another underground process is created you will kill that process instead of the one you wanted to kill as $! returns the PID of the last background process.

    i pointed this out because kill is used here.
    I know very little about the bash source so I can't demonstrate it with code bits. I don't know either if this race condition is possible or not. Note that $! is shell specific, and as such, only processes being launched in the sub-shell where the script is running could have any chance to interfere.

    Whether it's possible that this happens or not depends exclusively on how bash handles it. As I said, I can't demonstrate it with code bits, but I write scripts using that very often, and I have never seen that fail. It's just an empirical fact, though I know that, strictly speaking, that demonstrates absolutely nothing.

    Maybe someone more knowledgeable about the bash internals could help here.

  7. #7
    Linux Engineer khafa's Avatar
    Join Date
    Apr 2008
    Location
    Tokyo, Japan
    Posts
    858
    i92guboj,

    for the first point i meant to use grep before awk. as "jobs -l" returns the process name you can grep for it. and awk will return the last id of that process name and the result will be "the same " as the one from the solution you gave.

    for the second point sorry if got myself misunderstood. as i said i just wanted to warn the user not to create any background process between those 2 commands.
    that is why i wrote that this is less likely to happen and that i pointed it out because kill is used.
    as you said
    Note that $! is shell specific, and as such, only processes being launched in the sub-shell where the script is running could have any chance to interfe
    this does not happen if the sub-shell does not launch another background process before getting the PID.
    Linux and me it's a love story

  8. #8
    Linux Engineer Freston's Avatar
    Join Date
    Mar 2007
    Location
    The Netherlands
    Posts
    1,049
    This is overcomplicating the question IMHO. Sure there are interesting thoughts here, but I don't think we need such subtleties in BASH scrips to just kill a proces with a known name at a certain time.

    I wrote this script once, and I admit it's ugly but it works.

    Code:
    #!/bin/bash
    # stop v0.03
    
    if [ ! $1 ] ; then
            echo "Stop what?"
    else
            for i in `ps aux | grep -i $1 | grep -v grep | awk '{print $2}' ` ; do
            kill $i
    done
    exit 0
    fi
    If you call this from cron with process_name as argument, it'll cycle through the output of ps aux and kill every occurrence of process_name.

    Or... as a matter of fact, it kills every instance of $pattern that is given as an argument. So that could be anything. Every process owned by $user or even $root (with the right permissions). But I digress.

    What's needed now is a timer. I know there is the 'at' command, allowing you to run commands at certain times. There is the 'after command' allowing you to run a command after a certain interval. But these don't seem to want to work on my machine, and I haven't looked into it further. It might work on your machine.

    Also, scheduling the stop command in cron seems a good option.

    Or, if you'd rather use an interval based timer rather than a ... ehm ... clock time based timer, then you might even construct a timer within the original command. That has the benefit of not having to run two seperate commands. Just one that kills itself after a certain elapsed amount of time. It can be done.

    Maybe the OP can clarify how he'd like it to work?
    Can't tell an OS by it's GUI

  9. #9
    Linux Guru
    Join Date
    Nov 2007
    Location
    Córdoba (Spain)
    Posts
    1,513
    Quote Originally Posted by Freston View Post
    This is overcomplicating the question [...]
    Code:
    #!/bin/bash
    # stop v0.03
    
    if [ ! $1 ] ; then
            echo "Stop what?"
    else
            for i in `ps aux | grep -i $1 | grep -v grep | awk '{print $2}' ` ; do
            kill $i
    done
    exit 0
    fi
    If you call this from cron with process_name as argument, it'll cycle through the output of ps aux and kill every occurrence of process_name.
    Errm... *That* indeed is overcomplicating the things. Not only the script is far more complex than the two above, but also you are involving "cron" and/or "at", something that's not needed for the task. A simple sleep will work.

    He just want to launch a task, and stop it after a given time.

    Just launch, save pid, sleep, kill pid. That's what the scripts above do, and there's no easier (nor shorter) way.

    If you want versatility, just parametrize the file name and the sleep time, or whatever you need.

  10. #10
    Linux Engineer Freston's Avatar
    Join Date
    Mar 2007
    Location
    The Netherlands
    Posts
    1,049
    Sorry 'bout my tone of voice in my previous post. I did sound more harsh than I intended.

    Quote Originally Posted by Prototerm
    The above script, when run directly, does exactly what I want, with no unnecessary overhead. I can start it with a cron job if I want, but how do I stop it at a particular time of day, or after a specific elapsed time?
    The OP has a script to start the process. My (generic) script can be used to stop it again at a particular time of day. So what you have here is a two stage rocket, with reusable parts (and I already admitted it's ugly). I brought it up because there was some disagreement on using killall. Which was in my opinion the easiest way to solve this.

    I'll readily admit my script wants a rewrite for the particular purpose of the OP. But bear with me. If the question is how to stop a process at a certain time, rather than after a certain interval, then I see no way how to avoid either a two stage rocket, or the 'at' command.

    If an interval trigger suffices, then the below script is much cleaner than any two stage rocket will ever be.
    Code:
    #!/bin/sh
    cat /dev/video0 > /data/capture/$1 &
    _pid="`jobs -l | awk '{print $2}'`"
    sleep <no. of seconds>
    kill -TERM $_pid
    Yet, I can see how this works from the command line. But pray, tell me, does this work when run from cron? Because I took it that was the intend of the OP, to schedule from cron. It's clear that my knowledge here is failing me. I would have thought that jobs does not list cronjobs as they are already ran in the background anyway. Hence my preference for using 'ps aux | grep patern'. If jobs does return cronjob pids in this way I admit this is a much cleaner solution.


    ___
    Again, sorry for my tone of voice. Being Dutch I often find I lack the necessary ability to play with the English language so that how I write reflects how I intend.
    We all agree it's just a matter of 'start - wait for trigger - stop' sequence. But how this is implemented is subject to discussion. I seem to have focused more on the clock time trigger, whereas my fellow posters focused on an interval trigger. If that was cause for misunderstanding, then that was my fault. I should have been more careful in how I worded my thoughts.
    Can't tell an OS by it's GUI

Page 1 of 2 1 2 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •