通配符:返回源路径

通配符:返回源路径

我正在尝试将在同一文件夹中找到的每个access.log.gz文件(注意:确切的文件名,而不是“以...开头”或“包含”) 。/home/*/logsdate-access.log.gz

for file in /home/*/logs/access.log.gz
do
   mv -v "$file" /home/*/logs/old/`date +\%G-\%m-\%d`"-access.log.gz"
done

我当然得到了/home/*/logs/2014-09-08-access.log.gz - No such file or directory。我该如何调用*路径?每个文件都应重命名并移动到源文件夹的 /old/ 子目录。我尝试过

mv -v "$file" /home/`$1`/logs/old/`date +\%G-\%m-\%d`"-access.log.gz"

...但没有作用。

答案1

使用find如何更有效地使用 find 命令?)。

find /home/ -ipath */logs/access.log.gz

这样应该可以找到您感兴趣的所有文件并打印它们。您可以将其插入到脚本中,但让其 find完成所有艰苦的工作可能更容易。

find /home/ -ipath */logs/access.log.gz -execdir mv "{}" "old/`date +\%G-\%m-\%d`-access.log.gz" \;

find我们在这里使用的功能是:

  • -ipath-name与找到的文件名中的模式匹配。如果您确定每个子路径中只有一个 access.log.gz 文件,也可以使用( -name access.log.gz)。
  • -execdir从包含匹配文件的子目录中对每个找到的文件执行给定的命令。这相当于对cd每个文件所在的位置执行操作,然后在那里运行命令。在这种情况下,它节省了大量的路径操作逻辑。找到的文件将替换 {}。还要注意,“old”是作为相对路径给出的(正如您所说的,它old/存在于 中logs/

答案2

$file在迭代匹配的文件时,只需简单地剖析并重新组装:${file%/*}为您提供包含最后一次/删除之后的所有内容的 $file,并${file##*/}为您提供包含最后一次/删除之前的所有内容的 $file;结合起来${file%/*}/old/$date-${file##*/}会为您提供对应于的“新”文件名$file

假设在运行脚本的过程中日期不会改变,因此没有必要date对每个文件都调用它;相反,将日期存储在一个变量中一次,然后在循环期间使用它:date=$(date '+%G-%m-%d')。(请注意,现代脚本应该使用$(...)而不是反引号。还要注意,这%不是一个“特殊”字符,因此不需要引用或转义,但作为一种良好做法,整个格式字符串都应该被引用。)

如果您有新版本的 Bash,则可以通过使用来完全避免使用子 shell printf -v date '%(%G-%m-%d)T' -1

您可能还会发现它很有用,shopt -s globstar这样您就可以在目录中搜索任意深度,并且shopt -s nullglob不匹配的 glob(通配符)将扩展为“无”而不是原始的 glob 模式。

综合以上,我们得到:

shopt -s globstar nullglob
date=$( date '+%G-%m-%d' )
for file in /home/*/logs/**/access.log.gz
do
    target=${file%/*}/old/$date-${file##*/}
    mv -vi "$file" "$target"
done

答案3

如果你有安装,使用zmv. 在脚本中:

#!/bin/zsh
autoload zmv
zmv '/home/*/logs/access.log.gz' '$f:h/`date +\%G-\%m-\%d`-$f:t'

在 zsh 命令行上,输入autoload zmv您的~/.zshrc并在命令提示符下运行最后一行。

相关内容