方法一

方法一

我有一个目录,其文件名不断变化(按数值),列出为:

    -rw-rw----. 1 root root 10493952 May  7 10:39 A0000000.LOG
    -rw-rw----. 1 root root 10493952 May  7 08:38 A0000001.LOG
    -rw-rw----. 1 root root 10493952 May  7 08:38 A0000002.LOG
    ...
    ...
    -rw-rw----. 1 root root 10493952 May  7 08:38 A0000582.LOG
    ...
    and so on...

现在,在任何给定时刻,我的应用程序都会从​​这些列出的文件中抛出一个文件名。我必须丢弃文件和具有大于数值的任何其他文件文件从 rsyncing 到远程主机

假设应用程序抛出 file A0000096.LOG。如果我 A0000097.LOG也看到被创造,我会::

rsync A* --exclude A0000096.LOG --exclude A0000097.LOG user@remoteHost:/somedir/
  • 注意事项:

    • 应用程序向每小时运行的 rsync cron 作业抛出不同的文件名。在此示例中,文件名是A0000096.LOG

    • 数值高于应用程序输出文件名的文件(A0000096.LOG在上面的示例中)可以具有与应用程序输出文件名相同的创建日期/时间戳

    • 当 rsync 启动时,应用程序的输出文件名可以比具有更高数值的文件具有更新的日期/时间戳。

    • 可能无法创建更高数值的文件,或者创建的文件数量可能超过 1 个(可能是 10 到 20 个)

问题:由于这些限制,我无法找到如何向我的 rsync bash 脚本提供所有更高数值的文件,以便我可以排除它们。

任何帮助表示赞赏。

答案1

如果我正确理解了这个问题,您希望A0000000通过.rsync 范围内的所有文件进行 rsync A0000095。好吧,那么,别说A*;使用正通配符列表(也称为 glob 或文件名扩展模式)来生成所需的文件名,而不是标识要排除的文件名。通过将范围分解为子范围来实现:

         Subrange                         Wildcard
    A0000000-A0000089                 A00000[0-8][0-9]
    A0000090-A0000095                 A000009[0-5]

所以你会说

rsync A00000[0-8][0-9] A000009[0-5] user@remoteHost:/somedir/

如果您无法从一个示例中推广这种方法,请考虑 97169。

         Subrange                           Wildcard
    A0000000-A0089999                 A00[0-8][0-9][0-9][0-9][0-9]
    A0090000-A0096999                 A009[0-6][0-9][0-9][0-9]
    A0097000-A0097099                 A00970[0-9][0-9]
    A0097100-A0097159                 A00971[0-5][0-9]
    A0097160-A0097168                 A009716[0-8]

可以想象,其中一些通配符将与任何现有文件不匹配。在这种情况下,做

shopt -s nullglob

告诉 shell 继续运行命令,rsync并忽略失败的通配符(即扩展为 null)。

答案2

由于数字用零填充到相同的宽度,因此数字顺序与字典顺序相同。因此,您的问题相当于删除按词法顺序以给定文件开头的文件。

您可以通过构建一个包含由换行符分隔的文件名的字符串,并使用字符串替换来删除字符串的末尾,然后依靠不带引号的扩展将截断的字符串转回列表来完成此操作。我假设文件名中没有换行符,并且您的 shell 是 bash 或 ksh(使用普通 sh,您需要使用位置参数而不是命名数组)。

nl=$'\n'                              # newline, we use it as a separator
cut_from=A0000096.LOG
log_files=(A???????.LOG)
set -f; IFS="$nl"                     # disable wildcard expansion and set the word separator to newline only
log_files="$nl${log_files[*]}$nl"     # turn the array into a string with newlines separating elements
log_files=(${log_files%"$nl$cut_from$nl"})    # remove elements from $cut_from onwards and split the string into an array
unset IFS; set +f
rsnyc -a "${log_files[@]}" … elsewhere:/some/dir

答案3

回答我自己的问题:

方法一

  CUT_LOG=A0000096.LOG        #Assuming app throws a file - A0000096.LOG and I've to exclude this and any other files having higher numerical value than this file: A0000096.LOG. e.g. A0000097.LOG etc.

   LISTLOG=`ls -1 /Source_Dir/A*.LOG | sed "/$CUT_LOG/,$ d"`       # Instantiate a variable - LISTLOG, that will hold files list excluding A0000096.LOG and any other files having higher numerical value than this A0000096.LOG


      rsync -a `echo "${LISTLOG[@]}"` user@remoteHost:/somedir/    # Transfers the files excluding A0000096.LOG and excluding any other files with higher numerical values than A0000096.LOG

方法2【使用循环(不推荐)

        for line in `echo "${LISTLOG[@]}"`; do                     # Recursively loop through the array and rsync each entry
                rsync -a $line user@remoteHost:/somedir/
        done

答案4

切线关闭吉尔斯的观察您的文件名按词法排序,您可以使用它zsh为 rsync 创建过滤器文件:

cut_log=A0000096.LOG zsh -c 'logfilter() { ! [[ "$REPLY" < "$cut_log" ]] }; print -l A*.LOG(+logfilter)' > .exclude_file
rsync A* --exclude-from=.exclude_file user@remoteHost:/somedir/
rm .exclude_file

当然,您可以在 zsh 中本地完成这一切,但我正在演示如何使用有用的 zsh 功能扩展您的 bash 脚本。这个功能被称为“全球预选赛”eString并在和部分中进行了描述+cmd。它要求A*.LOG通过将每个候选者传递给给定的函数来扩展过滤。该函数的参数名为REPLY,因此我们在词法上将其与 的值进行比较,$cut_log以确定在结果列表中包含或排除。

上面假设代码在包含日志文件的目录中执行,以便rsync找到它们并找到zsh它们。

.exclude_file这样可以通过在执行命令之前检查来轻松进行空运行rsync

如果您发现文件过多包括在命令行上(这样命令会因为参数太多而失败),但参数足够少排除文件,您可以反转逻辑并告诉rsync文件--include-from,然后切换logfilter逻辑以删除反转 ( !)。

相关内容