如何定期运行bash命令?

jer*_*ome 45 bash

我想执行一个脚本并让它每x分钟运行一次命令.

关于学习bash脚本的任何资源的任何一般建议都可能非常酷.我使用Linux进行个人开发工作,所以bash脚本对我来说并不完全陌生,我只是从头开始编写自己的任何东西.

Gil*_*not 71

如果要定期运行命令,有3种方法:

  • 使用crontab命令ex.* * * * * command(每分钟运行一次)
  • 使用循环如:( while true; do ./my_script.sh; sleep 60; done不精确)
  • 使用systemd计时器

cron

有关最佳bash脚本实践的一些指示:

http://mywiki.wooledge.org/BashFAQ
指南:http://mywiki.wooledge.org/BashGuide
REF:http://www.gnu.org/software/bash/manual/bash.html
HTTP://维基.bash-hackers.org /
使用更多引用!:http://www.grymoire.com/Unix/Quote.html
Scripts等:http://www.shelldorado.com/

  • 我不知道*更好*和*更糟*的选择.他们都有自己的优点和缺点.cron方法的一个缺点是您可以同时运行多个命令实例.前景*while循环*示例不会发生这种情况. (3认同)
  • Crontab是更好的选择,特别是如果您想“永久”运行(很长时间)。 (2认同)
  • 真的取决于你想做什么.*while循环*将退出*sync*(无论如何).如果你必须时间准确,循环将不起作用(至少不那么容易). (2认同)

Yos*_*ian 19

除了@ sputnick的回答,还有watch.从手册页:

Execute a program periodically, showing output full screen
Run Code Online (Sandbox Code Playgroud)

默认情况下,这是每2秒.例如watch,tail对日志很有用.

  • 对于`tail`ing日志,你最好使用`tail -f $ filename` (6认同)
  • 重要的是要指出`watch`是非标准的,默认情况下在大多数非GNU系统(包括Mac)上都不存在. (3认同)

Kir*_*kow 8

    \n
  • 如果您需要定期运行命令以便可以监视其输出,请使用watch [options] command。例如,要监视可用内存,请运行:
  • \n
\n
watch -n 1 free -m\n
Run Code Online (Sandbox Code Playgroud)\n

\xe2\x80\x82\xe2\x80\x82\xe2\x80\x82\xe2\x80\x82该-n 1选项将更新间隔设置为 1 秒(默认为 2 秒)。

\n

\xe2\x80\x82\xe2\x80\x82\xe2\x80\x82\xe2\x80\x82详细信息请man watch查看或在线手册

\n
\n
    \n
  • 如果您需要监视一个或多个文件(通常是日志)的更改,tail您可以选择命令,例如:
  • \n
\n
# monitor one log file\ntail -f /path/to/logs/file.log\n# monitor multiple log files concurrently\ntail -f $(ls /path/to/logs/*.log)\n
Run Code Online (Sandbox Code Playgroud)\n

\xe2\x80\x82\xe2\x80\x82\xe2\x80\x82\xe2\x80\x82 -f(对于 \xe2\x80\x9cfollow\xe2\x80\x9d)选项告诉tail随着文件的增长输出新内容。

\n

\xe2\x80\x82\xe2\x80\x82\xe2\x80\x82\xe2\x80\x82详细信息请man tail查看或在线手册

\n


mkl*_*nt0 7

macOS用户:这是用于主要视觉检查的交互式定期调用的GNU 命令(从版本开始)的部分实现watch:0.3.0

它与GNU版本语法兼容,如果使用未实现的功能,则会失败并显示特定的错误消息.

显着的局限性:

  • 输出不限于一个屏幕.
  • 不支持显示输出差异.
  • 不支持使用精确计时.
  • 彩色输出总是通过(--color隐含).

还实现了一些非标准功能,例如等待success(-E)以补充等待error(-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.
Run Code Online (Sandbox Code Playgroud)

源代码(粘贴到一个名为的脚本文件中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 "$@"; 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 "$@" 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)]: $@"$'\n' >&3
  if (( useExec )); then
    (exec "$@")  # 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.
      "$@"
    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
Run Code Online (Sandbox Code Playgroud)