当我尝试根据文件名中包含的日期将一系列文件从一个目录复制到另一个目录时,我遇到了问题。文件名中的日期采用 UTC 时间,而创建日期采用 CST 时间。目录中包含的所有文件名都具有与此类似的文件名:
foo_20160227_0015.gif
foo_20160227_0030.gif
.....
.....
foo_20160304_0030.gif
foo_20160304_0045.gif
我尝试使用的脚本如下:
# Variables
strPrevDay=$(date +"%Y%m%d" -d "yesterday")
str7DaysAgo=$(date +"%Y%m%d" -d "7 days ago")
strImgDir="~/Documents/Projects/Radar/Images/"
strTmpImgDir="~/Documents/Projects/Radar/Images/Temp/"
strFileName="foo_"
strFile=
# Copy files created in the last week
for f in $strImgDir$strFileName{$str7DaysAgo..$strPrevDay}*.gif; do cp "$f" $strTmpImgDir; done
脚本运行后,我收到以下错误消息:
cp: cannot stat ‘/home/user/Documents/Projects/Radar/Images/foo_{20160227..20160304}*.gif’: No such file or directory
答案1
出现此错误的原因是{$str7DaysAgo..$strPrevDay}
首先展开大括号(由于它不是 形式,因此不会执行任何操作),然后展开变量。这是一个 bash 陷阱。{NUMBER1..NUMBER2}
7天,用 来列举天数并不是没有道理的date
。看杰夫·夏勒的回答。
另一种选择是用于eval
强制评估按所需顺序进行。使用eval
很容易出错,因为您需要非常小心被评估两次的部分,但这里我们知道文件名的部分只包含数字,所以没关系。请注意,您需要打开该nullglob
选项以防有几天没有生成文件。
#!/bin/bash
last_day=$(date +"%Y%m%d" -d "yesterday")
first_day=$(date +"%Y%m%d" -d "7 days ago")
eval "all_days=({$first_day..$last_day})"
image_directory=~/Documents/Projects/Radar/Images/
temporary_directory="$image_directory/Temp/"
filename_prefix="foo_"
shopt -s nullglob
for day in "${all_days[@]}"; do
files=("$image_directory/$filename_prefix$day"*.gif)
if [[ ${#files[@]} != 0 ]]; then
cp "${files[@]}" "$temporary_directory"
fi
done
(我还修复了你的引用 - 以及你难以阅读的变量名称。请注意,VAR="~/something"
在 中放置一个波浪号VAR
,您需要将波浪号保留为未加引号才能获取主目录。然后 Bash 扩展波浪号,因为您有一个未加引号的变量扩展,如果目录名称包含空格或其他 shell 特殊字符,这会中断 - 不要将变量不加引号,除非您知道这是必要的。)
另一种方法是枚举文件并仅复制所需范围内的文件。对于大范围来说,这可能会更快,因为每次使用通配符都必须枚举目录中的文件(没有更快的方法来获取与特定模式匹配的文件)。
#!/bin/bash
last_day=$(date +"%Y%m%d" -d "yesterday")
first_day=$(date +"%Y%m%d" -d "7 days ago")
image_directory=~/Documents/Projects/Radar/Images/
temporary_directory="$image_directory/Temp/"
filename_prefix="foo_"
shopt -s nullglob
for file in "$image_directory/$filename_prefix"*.gif; do
file_date="${file##*/"$filename_prefix"}"; file_date=${file_date:0:8}
if ((file_date >= first_day && file_date <= last_day)); then
cp "$file" "$temporary_directory"
fi
done
答案2
由于您似乎有 GNU 日期,因此这里有一个简单的解决方案:
#!/usr/bin/env bash
str7DaysAgo=$(date +"%Y%m%d" -d "7 days ago")
str6DaysAgo=$(date +"%Y%m%d" -d "6 days ago")
str5DaysAgo=$(date +"%Y%m%d" -d "5 days ago")
str4DaysAgo=$(date +"%Y%m%d" -d "4 days ago")
str3DaysAgo=$(date +"%Y%m%d" -d "3 days ago")
str2DaysAgo=$(date +"%Y%m%d" -d "2 days ago")
str1DaysAgo=$(date +"%Y%m%d" -d "1 days ago")
strImgDir="~/Documents/Projects/Radar/Images/"
strTmpImgDir="~/Documents/Projects/Radar/Images/Temp/"
strFileName="foo_"
base="${strImgDir}${strFileName}"
# Copy files created in the last week
for f in ${strImgDir}/*.gif
do
if [[ "$f" =~ ${strFileName}${str7DaysAgo} || \
"$f" =~ ${strFileName}${str6DaysAgo} || \
"$f" =~ ${strFileName}${str5DaysAgo} || \
"$f" =~ ${strFileName}${str4DaysAgo} || \
"$f" =~ ${strFileName}${str3DaysAgo} || \
"$f" =~ ${strFileName}${str2DaysAgo} || \
"$f" =~ ${strFileName}${str1DaysAgo} \
]]
cp "$f" $strTmpImgDir
fi
done