根据条件在无限循环中运行带有While条件的shell脚本

时间:2014-04-25 21:22:48

标签: shell if-statement for-loop while-loop conditional-statements

我需要创建一个shell脚本,根据从目录/dir1/dir2/flag_file_directory中的shell脚本收到的请求标志和目录中的源文件,将一些指示符/标志文件放在一个名为/dir1/dir2/req_flag_file_directory的目录中。目录说dir1/dir2/source_file_directory。为此,我需要在无限循环中使用 while 条件运行脚本,因为我不知道源文件何时可用。

所以,我的实施计划有点像这样 - 假设 JOB1 计划在早上的某个时间运行将首先(触摸)请求标志(例如,touch / dir1 / dir2 / req_flag_file_directory / req1.req),表示此作业正在运行,因此查找源文件目录中存在的模式file_pattern_YYYYMMDD.CSV的源文件(不同作业的文件模式不同),如果它们存在,然后计算数字。如果文件计数正确,则首先删除此作业的请求标志,然后touch /dir1/dir2/flag_file_directory中的指示符/标志文件。然后,此指标/标志文件将用作指示源文件全部存在,并且可以继续作业将这些文件加载​​到我们的系统中。

我将把有关作业及其标志文件的所有细节都放在一个文件中,其结构如下所示。根据请求标志,脚本应该在放置指标文件之前知道它应该寻找的其他标准:

request_flags|source_name|job_name|file_pattern|file_count|indicator_flag_file
req1.req|Sourcename1|jobname1|file_pattern_1|3|ind1.ind
req2.req|Sourcename2|jobname2|file_pattern_2|6|ind2.ind
req3.req|Sourcename3|jobname3|file_pattern_3|1|ind3.ind
req**n**.req|Sourcename**n**|jobname**n**|file_pattern_**n**|2|ind**n**.ind

如果您有其他建议或解决方案,请告诉我如何实现这一目标

2 个答案:

答案 0 :(得分:2)

而是让服务守护程序脚本在无限循环中轮询(即定期唤醒以检查它是否需要工作),您可以使用文件锁定和命名管道来创建事件队列。

服务守护程序概述daemon.sh。这个脚本将无限循环,通过从read line的命名管道读取来阻塞,直到消息到达(即,其他一些进程写入$RequestPipe)。

#!/bin/bash
#   daemon.sh

LockDir="/dir1/dir2/req_flag_file_directory"
LockFile="${LockDir}/.MultipleWriterLock"
RequestPipe="${LockDir}/.RequestQueue"

while true ; do

    if read line < "$RequestPipe" ; then
        # ... commands to be executed after message received ...
        echo "$line"            # for example
    fi

done



requestor.sh的大纲,该脚本在一切准备就绪时唤醒服务守护程序。该脚本完成了所有必要的准备工作,例如在req_flag_file_directorysource_file_directory中创建文件,然后通过写入命名管道唤醒服务守护程序脚本。它甚至可以发送一条消息,其中包含服务守护程序的更多信息,例如&#34;作业1就绪&#34;。

#!/bin/bash
#   requestor.sh

LockDir="/dir1/dir2/req_flag_file_directory"
LockFile="${LockDir}/.MultipleWriterLock"
RequestPipe="${LockDir}/.RequestQueue"

# ... create all the necessary files ...

(
    flock --exclusive 200
    #   Unblock the service daemon/listener by sending a line of text.
    echo Wake up sleepyhead. > "$RequestPipe"
) 200>"$LockFile"       # subshell exit releases lock automatically



daemon.sh充实了一些错误处理:

#!/bin/bash
#   daemon.sh

LockDir="/dir1/dir2/req_flag_file_directory"
LockFile="${LockDir}/.MultipleWriterLock"
RequestPipe="${LockDir}/.RequestQueue"
SharedGroup=$(echo need to put a group here 1>&2; exit 1)


#
if [[ ! -w "$RequestPipe" ]] ; then
    #    Handle 1st time. Or fix a problem.
    mkfifo --mode=775 "$RequestPipe"
    chgrp "$SharedGroup" "$RequestPipe"
    if [[ ! -w "$RequestPipe" ]] ; then
        echo "ERROR: request queue, can't write to $RequestPipe" 1>&2
        exit 1
    fi
fi

while true ; do

    if read line < "$RequestPipe" ; then
        # ... commands to be executed after message received ...
        echo "$line"        # for example
    fi

done



requestor.sh充实了一些错误处理:

#!/bin/bash
#   requestor.sh

LockDir="/dir1/dir2/req_flag_file_directory"
LockFile="${LockDir}/.MultipleWriterLock"
RequestPipe="${LockDir}/.RequestQueue"
SharedGroup=$(echo need to put a group here 1>&2; exit 1)

# ... create all the necessary files ...

#
if [[ ! -w "$LockFile" ]] ; then
    #    Handle 1st time. Or fix a problem.
    touch "$LockFile"
    chgrp "$SharedGroup" "$LockFile"
    chmod 775 "$LockFile"
    if [[ ! -w "$LockFile" ]] ; then
        echo "ERROR: write lock, can't write to $LockFile" 1>&2
        exit 1
    fi
fi
if [[ ! -w "$RequestPipe" ]] ; then
    #    Handle 1st time. Or fix a problem.
    mkfifo --mode=775 "$RequestPipe"
    chgrp "$SharedGroup" "$RequestPipe"
    if [[ ! -w "$RequestPipe" ]] ; then
        echo "ERROR: request queue, can't write to $RequestPipe" 1>&2
        exit 1
    fi
fi

(
    flock --exclusive 200 || {
        echo "ERROR: write lock, $LockFile flock failed." 1>&2
        exit 1
    }
    #   Unblock the service daemon/listener by sending a line of text.
    echo Wake up sleepyhead. > "$RequestPipe"

) 200> "$LockFile"      # subshell exit releases lock automatically

答案 1 :(得分:1)

对请求文件的内容仍有疑问,但我想我已经提出了一个相当简单的解决方案:

#!/bin/bash

DETAILS_FILE="details.txt" 
DETAILS_LINES=$((`wc -l $DETAILS_FILE|awk '{print $1}'`-1)) # to remove banner line (first line)
DETAILS=`tail -$DETAILS_LINES $DETAILS_FILE|tr '\n\r' ' '`
PIDS=()
IFS=' '

waitall () { # PIDS...
  ## Wait for children to exit and indicate whether all exited with 0 status.
  local errors=0
  while :; do
    debug "Processes remaining: $*"
    for pid in $@; do
      echo "PID: $pid"
      shift
      if kill -0 "$pid" 2>/dev/null; then
        debug "$pid is still alive."
        set -- "$@" "$pid"
      elif wait "$pid"; then
        debug "$pid exited with zero exit status."
      else
        debug "$pid exited with non-zero exit status."
        ((++errors))
      fi
    done
    (("$#" > 0)) || break
    # TODO: how to interrupt this sleep when a child terminates?
    sleep ${WAITALL_DELAY:-1}
  done
  ((errors == 0))
}

debug () { echo "DEBUG: $*" >&2; }

#function to check for # of sourcefiles matching pattern in dir
#params: req3.req Sourcename3 jobname3 file_pattern_3 1 ind3.ind
check () {
  NOFILES=`find $2 -type f | egrep -c $4`
  if [ $NOFILES -eq "$5" ];then
    echo "Touching file $6. done."
    touch $6
  else
    echo "$NOFILES matching $4 pattern. exiting"
  fi
}

echo "parsing $DETAILS_FILE file..."
read -a lines <<< "$DETAILS"

for line in "${lines[@]}"
do 
    IFS='|'
    read -a ARRAY <<< "$line"
    echo "Line processed. Dispatching job ${ARRAY[2]}..."
    check ${ARRAY[@]} &
    IFS=' '
    PIDS="$PIDS $!"
    #echo $PIDS
done

waitall ${PIDS}
wait

虽然不完全处于无限循环中。此脚本旨在在crontab中运行。

首先,根据您的示例,它会读取details.txt文件。

解析所有细节后,此脚本将调度check函数,其唯一目的是计算与每个file_pattern文件夹source_name匹配的文件数,如果文件数为等于file_count,然后触及indicator_flag_file

希望有所帮助!