두 사용자 입력 날짜 사이에 가능한 모든 날짜를 저장하고 싶습니다. 입력은 다음과 같습니다20140605그리고20140830.
루프를 사용하여 주어진 날짜 사이의 각 날짜를 변수에 저장하여 사용할 수 있도록 하고 싶습니다.
생성되거나 계산된 날짜는 입력과 동일한 형식이어야 합니다.
startdate=20141030
starttime=165800
enddate=20141120
endtime=175050
day=`expr $startdate % 100`
month=`expr $startdate % 10000`
year=`expr $startdate % 100000000`
month=`expr $month / 100`
year=`expr $year / 10000`
echo "$year $month $day"
while [ $enddate -ge $cdate ]
do
var=$cdate
#using variable var
if [ $day -eq 31 ]; then
cdate=`expr $cdate - $day`
day=1
((month++))
cdate=`expr $cdate + 100 + $day`
#cdate=`expr $cdate + $day`
if [ $month -eq 13 ]; then
#tmp=`expr $month \* 100`
cdate=`expr $cdate - $month \* 100`
month=1
((year++))
cdate=`expr $cdate + 10100`
if [ $year -eq 2999 ]; then
((year++))
echo $cdate
cdate=30010100
fi
fi
else
((day++))
((cdate++))
fi
if [ $enddate == $cdate ]; then
check=1
fi
done
나는 이런 방식으로 요구 사항을 구현하려고 노력합니다. 그러나 컴파일할 때 다음과 같이 말합니다.
단항 연산자가 필요합니다.
이 오류의 원인은 무엇입니까? 쉘 스크립트를 사용하여 이 문제를 어떻게 더 잘 해결할 수 있습니까?
답변1
나는 이 문제에 대해 완전히 다른 접근 방식을 취할 것입니다. 모든 날짜 계산을 수동으로 수행하면 오류가 발생하기 쉽습니다(한 달이 항상 31일이 아닌 경우, 윤년 등이 있음). 게다가 코드를 살펴보면 자신이 무엇을 하고 있는지 알기가 어렵습니다(이는 매우 나쁜 일입니다).
#!/bin/bash
startdate=20141030
enddate=20141120
dates=()
for (( date="$startdate"; date != enddate; )); do
dates+=( "$date" )
date="$(date --date="$date + 1 days" +'%Y%m%d')"
done
echo "${dates[@]}"
이는 date
명령을 사용하여 모든 계산을 처리하고 각 날짜를 $dates
배열에 저장합니다.
결과는 다음과 같습니다.
20141030 20141031 20141101 20141102 20141103 20141104 20141105 20141106 20141107 20141108 20141109 20141110 20141111 20141112 20141113 20141114 20141115 20141116 20141117 20141118 20141119
답변2
귀하의 의견에서 설명했듯이 최종 목표가 특정 날짜 범위 내에서 수정된 모든 파일을 찾는 것이라면 해당 범위를 변수에 저장할 필요가 없습니다. 대신 범위를 직접 제공할 수 있습니다 find
.
find . -mtime $start -mtime $end
개인적으로 나는 다른 접근법을 사용하고 싶습니다. 시작 날짜 1초 전과 종료 날짜 1초 후의 두 개의 임시 파일을 생성하기만 하면 됩니다. 그런 다음 GNU find의 -newer
테스트를 사용하여 첫 번째 파일보다 최신이고 후자보다 최신이 아닌 파일을 찾습니다.
까다로운 부분은 $start
바로 잡는 것입니다 $end
. 다음과 같이 시도해 볼 수 있습니다.
#!/usr/bin/env bash
## If you really want to use this format,
## then you must be consistent and always
## us YYYYMMDD and HHMMSS.
startdate=20141030
starttime=165800
enddate=20141120
endtime=175050
## Get the start and end times in a format that GNU date can understand
startdate="$startdate $( sed -r 's/(..)(..)(..)/\1:\2:\3/' <<<$starttime)"
enddate="$enddate $( sed -r 's/(..)(..)(..)/\1:\2:\3/' <<<$endtime)"
## GNU find has the -newer test which lets you find files
## that are newer than the target file. We can use this
## and create two temporary files with the right dates.
tmp_start=$(mktemp)
tmp_end=$(mktemp)
## Now we need a date that is one seond before the
## start date and one second after the end date.
## We can then use touch and date to set the creation date
## of the temp files to these dates.
minusone=$(date -d "$startdate -1 sec" +%s)
plusone=$(date -d "$enddate +1 sec" +%s)
## Set the creation times of the temp files.
## The @ is needed when using seconds since
## the epoch as a date string.
touch -d "@$minusone" $tmp_start
touch -d "@$plusone" $tmp_end
## At this point we have two files, tmp_start and
## tmp_end with a creation date of $startdate-1
## and $enddate+1 respectively. We can now search
## for files that are newer than one and not newer
## than the other.
find . -newer $tmp_start -not -newer $tmp_end
## Remove the temp files
rm $tmp_start $tmp_end