我有一个目录,其文件名不断变化(按数值),列出为:
-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
逻辑以删除反转 ( !
)。