【问题标题】:Run a shell script with While condition in an infinite loop based on conditions根据条件在无限循环中运行带有 While 条件的 shell 脚本
【发布时间】:2014-06-11 18:27:13
【问题描述】:

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

所以,我的实施计划有点像这样 - 假设 JOB1 计划在早上的某个时间运行,它将首先放置(触摸)请求标志(例如 touch /dir1/ dir2/req_flag_file_directory/req1.req),表示这个job正在运行,所以寻找源文件目录下patternfile_pattern_YYYYMMDD.CSV的Source files(不同job的文件pattern不同),如果存在,则数数。如果文件计数正确,则首先删除该作业的请求标志,然后删除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

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

【问题讨论】:

  • 您可能想调查inotify-tools 而不是重新发明这个轮子。
  • @Glenn,感谢您的建议,我浏览了 inotify 工具文档,它的文档并没有太大帮助。我没有看到如何在我的要求中使用它们。您能否建议或详细说明如何在我的情况下使用它们?
  • linux.die.net/man/1/inotifywait 可以监视目录中的事件,然后使用事件数据运行程序。 ...无需轮询(又名无限循环)
  • 请求文件的内容是什么?

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


【解决方案1】:

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

服务守护进程的概要,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 中创建文件,然后通过写入命名管道来唤醒服务守护程序脚本。它甚至可以发送一条消息,其中包含有关服务守护进程的更多信息,例如“Job 1 ready”。

#!/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

【讨论】:

    【解决方案2】:

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

    #!/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函数,其唯一目的是统计每个source_name文件夹中与file_pattern匹配的文件数,如果文件数等于file_count,然后触摸indicator_flag_file

    希望有帮助!

    【讨论】:

      猜你喜欢
      • 2019-12-10
      • 1970-01-01
      • 2014-06-07
      • 1970-01-01
      • 2014-04-30
      • 1970-01-01
      • 2022-11-12
      • 1970-01-01
      • 2021-11-26
      相关资源
      最近更新 更多