파일 이름에 포함된 날짜를 기준으로 일련의 파일을 한 디렉터리에서 다른 디렉터리로 복사하려고 할 때 문제가 발생합니다. 파일 이름의 날짜는 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}
중괄호가 먼저 확장된 다음(양식이 아니기 때문에 아무 작업도 수행하지 않음) 변수가 확장되기 때문에 발생합니다. 이것은 배쉬 트랩입니다.{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는 인용되지 않은 변수가 있기 때문에 물결표를 확장합니다. 확장(디렉토리 이름에 공백이나 기타 쉘 특수 문자가 포함된 경우 중단됨). 필요한 경우가 아니면 변수를 따옴표로 묶지 않은 상태로 두지 마십시오.
또 다른 접근 방식은 파일을 열거하고 원하는 범위 내의 파일만 복사하는 것입니다. 와일드카드를 사용할 때마다 디렉터리의 파일을 열거해야 하기 때문에 범위가 클 경우 더 빠를 수 있습니다(특정 패턴과 일치하는 파일을 얻는 더 빠른 방법은 없습니다).
#!/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