希望警报脚本在后台运行,但接受用户输入以停止它

时间:2014-01-20 20:18:12

标签: bash

我在http://milkteafuzz.com/j/2012/02/22/a-simple-bash-alarm-clock/找到一个非常简单但有效的警报脚本,以便在终端运行命令时接受用户输入,该终端可能是3个参数之一:警报日期时间,警报声音文件或警报标题 - 要显示的消息。如果没有读取输入,则脚本会使用默认声音文件和警报标题-msg提示用户输入警报的日期时间。

当闹钟响起时,我有一个读取命令,提示用户点击“Enter”键以停止闹钟。

我想让脚本在运行时在后台运行,但仍然允许用户停止警报(当然),但我似乎无法实现解决方案。

以下是我的内容(为了简洁省略了函数)。:

echo ""

#'if' user input $1 is supplied
if [[ -n "$1" ]] ; then
    if [[ "$1" =~ [0-2]{0,1}[0-9][:]{1}[0-9]{1,2} ]] ; then     #'if' input $1 matches date-time format
        date="$1" #; echo "\$date: ${date}"
    elif [[ "$1" =~ ^.*\.(mp3|ogg)$ ]] ; then   #'if' input $1 has mp3/ogg ext
        fChkFile "$1"   #funct call
    else    #'else' it is assumed input $1 is alarm title-msg to display when alarm goes off 
        msg="$1" #; echo "\$msg: ${msg}"
    fi
fi

#'if' user input $2 is supplied
if [[ -n "$2" ]] ; then
    fInput23 "$2"   #funct call
fi

#'if' user input $3 is supplied
if [[ -n "$3" ]] ; then
    fInput23 "$3"   #funct call
fi

if [[ -z "$date" ]] ; then      #'if' date-format IS null then not detected from user input and so prompt user for one
    printf "What time should the alarm sound? "
    read date
    if [[ -z "$date" ]] ; then      #'if' "$date" IS still null then abort
        notify-send "Aborting. A date-time format is required and none was detected."
        exit 67
    fi
fi

if [[ -z "$msg" ]] ; then       #'if' title-message IS null then assign default
    msg="The time has arrived to sit up and take notice..." #; echo "\$msg: ${msg}"
fi

if [[ -z "$sndF" ]] ; then      #'if' sound file IS null then assign default
    sndF="/media/multiMediaA_intHdA720Gb/music/theStrokes_isThisIt/07_lastNite.mp3" #; echo "\$sndF: ${sndF}"
fi

echo -e "\n\t\033[1;36mOkay! Will alert you on:\033[1;32m" $(date --date="$date")"\033[0m\n"

sleep $(( $(date --date="$date" +%s) - $(date +%s) ));
notify-send "$msg" -t 0
#while true; do
    /usr/bin/mpg123 -q -l 0 "$sndF" &
    sleep 1
    read -ep $'\n\033[1;33mHit Enter key to stop the alarm.\033[0m\n' killAlm
    #almPid=$(ps aux|grep "\/usr\/bin mpg123"|cut -d' ' -f3) #; echo "\$almPid: ${almPid}"
    almPid=$(ps aux|grep "\/usr\/bin mpg123"|sed -r 's/^[^ \t]*[ \t]*([0-9]{3,5})[ \t]*.*$/\1/') #; echo "$almPid"
    kill "$almPid"
#done

脚本运行正常且花花公子,但我真的不喜欢为每个警报集绑定终端的想法(我的记忆就像一个筛子,我倾向于在任何给定时间使用多个警报)。我如何运行脚本,接受输入(至少是日期时间var)然后在BG中运行,从而释放终端,但提示用户在一个人关闭时停止报警?

修改的: 使用屏幕可以正常工作,如下面的评论中所述。但由于某种原因,突然间(第一次,自尝试“屏幕”解决方案),挂起的mpg流程将无法清除,所以

kill "$almPid"

失败,因为它试图清除现在挂起的上一个进程。所以我添加了一个循环来循环通过所有mpg pids连续杀死每一个,虽然肯定不漂亮,似乎工作。好东西我用大胆的流媒体音乐,所以骑自行车杀死mpg pids不会破坏任何东西,除非当然有多个警报同时响起我猜。

    #almPid=$(ps aux|grep "\/usr\/bin mpg123"|sed -r 's/^[^ \t]*[ \t]*([0-9]{3,5})[ \t]*.*$/\1/') #; echo "$almPid"
    for p in $(ps aux|grep "\/usr\/bin mpg123"|sed -r 's/^[^ \t]*[ \t]*([0-9]{3,5})[ \t]*.*$/\1/') ; do
        # echo "\$p: $p"
        kill "$p"
    done

2 个答案:

答案 0 :(得分:2)

尝试使用"屏幕"命令

exemple here

答案 1 :(得分:0)

我认为没有办法强制调用shell将脚本带到前台。通常您可以使用fg手动执行此操作,按Enter键,然后使用CRTL-Z将其重新置于后台。

如果警报是唯一的后台作业(或最近的作业)fg本身就足够了。如果不是,您可以使用jobs查看后台进程的作业编号。将作业号作为fg的参数提供。

查看man bash的“JOB CONTROL”部分以获取更多信息。