2013-06-30 2 views
28

Я хочу выполнить скрипт и запустить его каждые x минут.Как я могу периодически запускать команду bash?

Также любые общие рекомендации по любым ресурсам для изучения сценариев bash могут быть действительно крутыми. Я использую Linux для своей личной работы по разработке, поэтому скрипты bash не совсем чужды мне, я просто не написал ничего с нуля.

+1

Вы посмотрели 'cron'? – SheetJS

+3

Что касается вашего запроса ресурсов, wiki-хакерский хакер имеет хорошо развитый [список ресурсов] (http://wiki.bash-hackers.org/scripting/tutoriallist), который явно обрезается, чтобы избежать руководства, которое не старайтесь избегать классических [ловушек] (http://mywiki.wooledge.org/BashPitfalls). – kojiro

ответ

53

Если вы хотите запустить команду периодически, есть 3 способа:

  • с помощью команды crontab отл. * * * * * command (ходят каждые минуты)
  • с помощью цикла, как: while true; do ./my_script.sh; sleep 60; done (не точные)
  • использования systemd timer

См cron

Некоторых указателей наилучшей практики Баша сценариев:

http://mywiki.wooledge.org/BashFAQ
Руководство: http://mywiki.wooledge.org/BashGuide
реф: http://www.gnu.org/software/bash/manual/bash.html
http://wiki.bash-hackers.org/
использовать более ЦИТАТЫ !: http://www.grymoire.com/Unix/Quote.html
Сценарии и многое другое: http://www.shelldorado.com/

+1

Crontab здесь лучший выбор, особенно если вы хотите запустить это «навсегда» (долгое время). – DaGardner

+3

Интересно, почему этот ответ был отклонен. –

+1

Хороший вопрос :) +1 для компенсации – DaGardner

2

Я хочу, чтобы запустить скрипт и запустить его команду каждый временной интервал {}

cron (https://en.wikipedia.org/wiki/Cron) был разработан для этой цели. Если вы запустите man cron или man crontab, вы найдете инструкции по его использованию.

любой общий совет по любым ресурсам для изучения сценариев bash может быть действительно круто. Я использую Linux для своей личной работы по разработке, поэтому скрипты bash не совсем чужды мне, я просто не написал ничего с нуля.

Если вам удобно работать с bash, я рекомендую сначала прочитать справочную страницу bash (man bash) - есть много крутых лакомых кусочков.

16

В дополнение к ответу @ sputnick, также есть watch. На странице руководства:

Execute a program periodically, showing output full screen 

По умолчанию это происходит каждые 2 секунды. watch полезен для журналов tail.

+3

Важно отметить, что 'watch' нестандартен и не существует на большинстве систем, отличных от GNU (включая Mac) по умолчанию. – kojiro

+6

для журналов 'tail'ing лучше использовать' tail -f $ filename' – Francisco

6

Macos пользователей: вот частичного реализации команды GNU watch (в версии 0.3.0) для интерактивных периодических вызовов для прежде всего визуальных проверки:

Это синтаксис совместим с версией GNU и с ошибкой с конкретным сообщением об ошибке, если используется нереализованная функция.

Известные ограничения:

  • Выход не ограничивается одной заполненного экрана.
  • Отображение разностей выходных сигналов не поддерживается.
  • Использование точной синхронизации не поддерживается.
  • Цветной выход Пробег (--color).

реализует также несколько нестандартных функций, таких как ожидание успеха (-E) в дополнение в ожидании ошибки (-e) и показывает время дня последнего вызова, а также прошло общее время так далеко.

Запустить watch -h для более подробной информации.

Примеры:

watch -n 1 ls # list current dir every second 
watch -e 'ls *.lockfile' # list lock files and exit once none exist anymore. 

Исходный код (вставить в файл сценария с именем watch, сделать его исполняемым, и поместить в каталог в вашем $PATH, обратите внимание, что подсветка синтаксиса здесь нарушается, но код работ):

#!/usr/bin/env bash 

THIS_NAME=$(basename "$BASH_SOURCE") 

VERSION='0.1' 

# Helper function for exiting with error message due to runtime error. 
# die [errMsg [exitCode]] 
# Default error message states context and indicates that execution is aborted. Default exit code is 1. 
# Prefix for context is always prepended. 
# Note: An error message is *always* printed; if you just want to exit with a specific code silently, use `exit n` directly. 
die() { 
    echo "$THIS_NAME: ERROR: ${1:-"ABORTING due to unexpected error."}" 1>&2 
    exit ${2:-1} # Note: If the argument is non-numeric, the shell prints a warning and uses exit code 255. 
} 

# Helper function for exiting with error message due to invalid parameters. 
# dieSyntax [errMsg] 
# Default error message is provided, as is prefix and suffix; exit code is always 2. 
dieSyntax() { 
    echo "$THIS_NAME: PARAMETER ERROR: ${1:-"Invalid parameter(s) specified."} Use -h for help." 1>&2 
    exit 2 
} 

# Get the elapsed time since the specified epoch time in format HH:MM:SS. 
# Granularity: whole seconds. 
# Example: 
# tsStart=$(date +'%s') 
# ... 
# getElapsedTime $tsStart 
getElapsedTime() { 
    date -j -u -f '%s' $(($(date +'%s') - $1)) +'%H:%M:%S' 
} 

# Command-line help. 
if [[ "$1" == '--help' || "$1" == '-h' ]]; then 
    cat <<EOF 

SYNOPSIS 
    $THIS_NAME [-n seconds] [opts] cmd [arg ...] 

DESCRIPTION 
    Executes a command periodically and displays its output for visual inspection. 

    NOTE: This is a PARTIAL implementation of the GNU \`watch\` command, for OS X. 
    Notably, the output is not limited to one screenful, and displaying 
    output differences and using precise timing are not supported. 
    Also, colored output is always passed through (--color is implied). 
    Unimplemented features are marked as [NOT IMPLEMENTED] below. 
    Conversely, features specific to this implementation are marked as [NONSTD]. 
    Reference version is GNU watch 0.3.0. 

    CMD may be a simple command with separately specified 
    arguments, if any, or a single string containing one or more 
    ;-separated commands (including arguments) - in the former case the command 
    is directly executed by bash, in the latter the string is passed to \`bash -c\`. 
    Note that GNU watch uses sh, not bash. 
    To use \`exec\` instead, specify -x (see below). 

    By default, CMD is re-invoked indefinitely; terminate with ^-C or 
    exit based on conditions: 
    -e, --errexit 
    exits once CMD indicates an error, i.e., returns a non-zero exit code. 
    -E, --okexit [NONSTD] 
    is the inverse of -e: runs until CMD returns exit code 0. 

    By default, all output is passed through; the following options modify this 
    behavior; note that suppressing output only relates to CMD's output, not the 
    messages output by this utility itself: 
    -q, --quiet [NONSTD] 
    suppresses stdout output from the command invoked; 
    -Q, --quiet-both [NONSTD] 
    suppresses both stdout and stderr output. 

    -l, --list [NONSTD] 
    list-style display; i.e., suppresses clearing of the screen 
    before every invocation of CMD. 

    -n secs, --interval secs 
    interval in seconds between the end of the previous invocation of CMD 
    and the next invocation - 2 seconds by default, fractional values permitted; 
    thus, the interval between successive invocations is the specified interval 
    *plus* the last CMD's invocation's execution duration. 

    -x, --exec 
    uses \`exec\` rather than bash to execute CMD; this requires 
    arguments to be passed to CMD to be specified as separate arguments 
    to this utility and prevents any shell expansions of these arguments 
    at invocation time. 

    -t, --no-title 
    suppresses the default title (header) that displays the interval, 
    and (NONSTD) a time stamp, the time elapsed so far, and the command executed. 

    -b, --beep 
    beeps on error (bell signal), i.e., when CMD reports a non-zero exit code. 

    -c, --color 
    IMPLIED AND ALWAYS ON: colored command output is invariably passed through. 

    -p, --precise [NOT IMPLEMENTED] 

    -d, --difference [NOT IMPLEMENTED] 

EXAMPLES 
    # List files in home folder every second. 
    $THIS_NAME -n 1 ls ~ 
    # Wait until all *.lockfile files disappear from the current dir, checking every 2 secs. 
    $THIS_NAME -e 'ls *.lockfile' 

EOF 
    exit 0 
fi 

    # Make sure that we're running on OSX. 
[[ $(uname) == 'Darwin' ]] || die "This script is designed to run on OS X only." 

# Preprocess parameters: expand compressed options to individual options; e.g., '-ab' to '-a -b' 
params=() decompressed=0 argsReached=0 
for p in "[email protected]"; do 
    if [[ $argsReached -eq 0 && $p =~ ^-[a-zA-Z0-9]+$ ]]; then # compressed options? 
    decompressed=1 
    params+=(${p:0:2}) 
    for ((i = 2; i < ${#p}; i++)); do 
     params+=("-${p:$i:1}") 
    done 
    else 
    ((argsReached && ! decompressed)) && break 
    [[ $p == '--' || ${p:0:1} != '-' ]] && argsReached=1 
    params+=("$p") 
    fi 
done 
((decompressed)) && set -- "${params[@]}"; unset params decompressed argsReached p # Replace "[email protected]" with the expanded parameter set. 

# Option-parameters loop. 
interval=2 # default interval 
runUntilFailure=0 
runUntilSuccess=0 
quietStdOut=0 
quietStdOutAndStdErr=0 
dontClear=0 
noHeader=0 
beepOnErr=0 
useExec=0 
while (($#)); do 
    case "$1" in 
    --) # Explicit end-of-options marker. 
     shift # Move to next param and proceed with data-parameter analysis below. 
     break 
     ;; 
    -p|--precise|-d|--differences|--differences=*) 
     dieSyntax "Sadly, option $1 is NOT IMPLEMENTED." 
     ;; 
    -v|--version) 
     echo "$VERSION"; exit 0 
     ;; 
    -x|--exec) 
     useExec=1 
     ;; 
    -c|--color) 
     # a no-op: unlike the GNU version, we always - and invariably - pass color codes through. 
     ;; 
    -b|--beep) 
     beepOnErr=1 
     ;; 
    -l|--list) 
     dontClear=1 
     ;; 
    -e|--errexit) 
     runUntilFailure=1 
     ;; 
    -E|--okexit) 
     runUntilSuccess=1 
     ;; 
    -n|--interval) 
     shift; interval=$1; 
     errMsg="Please specify a positive number of seconds as the interval." 
     interval=$(bc <<<"$1") || dieSyntax "$errMsg" 
     ((1 == $(bc <<<"$interval > 0"))) || dieSyntax "$errMsg" 
     [[ $interval == *.* ]] || interval+='.0' 
     ;; 
    -t|--no-title) 
     noHeader=1 
     ;; 
    -q|--quiet) 
     quietStdOut=1 
     ;; 
    -Q|--quiet-both) 
     quietStdOutAndStdErr=1 
     ;; 
    -?|--?*) # An unrecognized switch. 
     dieSyntax "Unrecognized option: '$1'. To force interpretation as non-option, precede with '--'." 
     ;; 
    *) # 1st data parameter reached; proceed with *argument* analysis below. 
     break 
     ;; 
    esac 
    shift 
done 

# Make sure we have at least a command name 
[[ -n "$1" ]] || dieSyntax "Too few parameters specified." 

# Suppress output streams, if requested. 
# Duplicate stdout and stderr first. 
# This allows us to produce output to stdout (>&3) and stderr (>&4) even when suppressed. 
exec 3<&1 4<&2 
if ((quietStdOutAndStdErr)); then 
    exec &> /dev/null 
elif ((quietStdOut)); then 
    exec 1> /dev/null 
fi 

# Set an exit trap to ensure that the duplicated file descriptors are closed. 
trap 'exec 3>&- 4>&-' EXIT 

# Start loop with periodic invocation. 
# Note: We use `eval` so that compound commands - e.g. 'ls; bash --version' - can be passed. 
tsStart=$(date +'%s') 
while :; do 
    ((dontClear)) || clear 
    ((noHeader)) || echo "Every ${interval}s. [$(date +'%H:%M:%S') - elapsed: $(getElapsedTime $tsStart)]: [email protected]"$'\n' >&3 
    if ((useExec)); then 
    (exec "[email protected]") # run in *subshell*, otherwise *this* script will be replaced by the process invoked 
    else 
    if [[ $* == *' '* ]]; then 
     # A single argument with interior spaces was provided -> we must use `bash -c` to evaluate it properly. 
     bash -c "$*" 
    else 
     # A command name only or a command name + arguments were specified as separate arguments -> let bash run it directly. 
     "[email protected]" 
    fi 
    fi 
    ec=$? 
    ((ec != 0 && beepOnErr)) && printf '\a' 
    ((ec == 0 && runUntilSuccess)) && { echo $'\n'"[$(date +'%H:%M:%S') - elapsed: $(getElapsedTime $tsStart)] Exiting as requested: exit code 0 reported." >&3; exit 0; } 
    ((ec != 0 && runUntilFailure)) && { echo $'\n'"[$(date +'%H:%M:%S') - elapsed: $(getElapsedTime $tsStart)] Exiting as requested: non-zero exit code ($ec) reported." >&3; exit 0; } 
    sleep $interval 
done 
Смежные вопросы