쉘 스크립트 bash: 월을 기준으로 파일 반복 이동

쉘 스크립트 bash: 월을 기준으로 파일 반복 이동

나는 쉘 스크립트에 대한 지식이 거의 없지만 불행히도 쉘 스크립트를 작성해야 합니다. bash 스크립트 반복 이동 파일에 대해 문의하고 싶은데 cronjob에서 실행할 월별로 정렬된 로그 파일을 이동해야 합니다. 계획은 mtime +30(1개월 전) 파일을 여러 폴더로 이동하고 cronjob이 매일 실행되는 것이었습니다. 예:

전에

/home/Work/LogFiles/20131200012.log
/home/Work/LogFiles/thisLogIsDifferent.log
/home/Work/LogFiles/20120322222.log 
/home/Work/LogFiles/20140100011.log
/home/Work/LogFiles/thisLogIsDifferent2.log

후에

/home/Work/LogFiles/thisLogIsDifferent.log
/home/Work/LogFiles/thisLogIsDifferent2.log
/home/Work/LogFiles/2013/DEC/20131200012.log
/home/Work/LogFiles/2012/MAR/20120322222.log 
/home/Work/LogFiles/2014/JAN/20140100011.log

나는 내가 사용해야했던 방법에 대한 단서를 얻지 못했습니다. 여기 내 끔찍한 쉘 스크립트가 있습니다:

BASE_DIR=/home/Work/LogFiles
REPORT_DIR_YEAR=$BASE_DIR/`date +%Y`
REPORT_DIR=$REPORT_DIR_YEAR/`date +%b`

NOW=$(date +"%Y%m")

if ! [ -d $REPORT_DIR_YEAR ]; then
    mkdir $REPORT_DIR_YEAR

    if ! [ -d $REPORT_DIR ]; then
        mkdir $REPORT_DIR
    fi
fi

#THIS PART NEED TO BE RE-ARRANGED
#What I expect is not date=NOW; BUT SOME KIND LIKE date %m-1? but I still don't have any ideas about modify date function.

for file in find $BASE_DIR -maxdepth 1 -type f -mtime +30 -name '*$NOW*'
do

 month=$(ls -l $file | awk '{ print $6 }')
    case "$month" in
      "Jan") mv $file $REPORT_DIR_YEAR/$month/$file echo "$file moved to $REPORT_DIR/$file";;
      "Feb") mv $file $REPORT_DIR_YEAR/$month/$file echo "$file moved to $REPORT_DIR/$file";;
      "Mar") mv $file $REPORT_DIR_YEAR/$month/$file echo "$file moved to $REPORT_DIR/$file";;
      "Apr") mv $file $REPORT_DIR_YEAR/$month/$file echo "$file moved to $REPORT_DIR/$file";;
      "May") mv $file $REPORT_DIR_YEAR/$month/$file echo "$file moved to $REPORT_DIR/$file";;
      "Jun") mv $file $REPORT_DIR_YEAR/$month/$file echo "$file moved to $REPORT_DIR/$file";;
      "Jul") mv $file $REPORT_DIR_YEAR/$month/$file echo "$file moved to $REPORT_DIR/$file";;
      "Aug") mv $file $REPORT_DIR_YEAR/$month/$file echo "$file moved to $REPORT_DIR/$file";;
      "Sep") mv $file $REPORT_DIR_YEAR/$month/$file echo "$file moved to $REPORT_DIR/$file";;
      "Oct") mv $file $REPORT_DIR_YEAR/$month/$file echo "$file moved to $REPORT_DIR/$file";;
      "Nov") mv $file $REPORT_DIR_YEAR/$month/$file echo "$file moved to $REPORT_DIR/$file";;
      "Dec") mv $file $REPORT_DIR_YEAR/$month/$file echo "$file moved to $REPORT_DIR/$file";;
          *) echo " Do nothing " ;;
    esac

done

그리고 그렇습니다. 이 경우는 $month이전 for 루프에서는 작동하지 않습니다 $file. 왜? 모르겠습니다. for 루프의 다양한 소스, 포럼, 예제에서 복사했지만 작동하지 않습니다.

답변1

우선, 그것은출력을 구문 분석하는 것은 결코 좋은 생각이 아닙니다.ls온갖 문제를 일으킬 수 있기 때문입니다. 파일의 나이를 얻는 더 좋은 방법은 stat. 예를 들어:

$ ls -l 20120322222.log 
-rw-r--r-- 1 terdon terdon 0 Jan  1  2012 20120322222.log
$ stat -c %y 20120322222.log 
2012-01-01 00:00:00.000000000 +0100

이제 우리는 파일의 나이를 구하는 방법을 알았습니다. 문제는 이를 세 글자의 월 이름으로 변환하는 방법입니다. 가장 쉬운 방법은 다음을 사용하는 것입니다 date.

 $ date -d "2012-01-01" +"%b"
Jan

두 명령을 결합하면 다음이 제공됩니다.

$ date -d "$(stat -c %y 20120322222.log)" +"%b"
Jan

따라서 이를 염두에 두고 다음과 같이 스크립트를 작성할 수 있습니다.

#!/usr/bin/env bash
BASE_DIR=/home/Work/LogFiles


## Find those files that are older than a month
find "$BASE_DIR" -maxdepth 1 -mtime +30 -type f -name "20*" | 
 while IFS= read -r file; do
    ## Get the file's modification year
    year="$(date -d "$(stat -c %y "$file")" +%Y)"
    ## Get the file's modification month
    month="$(date -d "$(stat -c %y "$file")" +%b)"

    ## Create the directories if they don't exist. The -p flag
    ## makes 'mkdir' create the parent directories as needed so
    ## you don't need to create $year explicitly.
    [[ ! -d "$BASE_DIR/$year/$month" ]] && mkdir -p "$BASE_DIR/$year/$month"; 

    ## Move the file
    mv "$file" "$BASE_DIR/$year/$month"
done

위의 스크립트는 이름을 구문 분석하는 것이 아니라 파일의 실제 수정 날짜를 얻고 싶다고 가정합니다. 대신 이름을 구문 분석하려면 알려주시면 그에 따라 수정하겠습니다.

답변2

terdon 덕분에: 나는 그/그녀의 스크립트를 가져와 OS X에서 작동하도록 수정했습니다. 또한 폴더 구조를 기본 월, 일 및 시간으로 변경했습니다.

#!/usr/bin/env bash
BASE_DIR=/Users/user/


## Find those files that are older than a month
find "$BASE_DIR" -maxdepth 1  -type f |
 while IFS= read -r file; do
    ## Get the file's modification month
    month="$(stat -f '%Sm' -t '%m' "$file")"
    ## Get the file's modification day
    day="$(stat -f '%Sm' -t '%d' "$file")"
    ## Get the file's modification hour
    hour="$(stat -f '%Sm' -t '%H' "$file")"


    ## Create the directories if they don't exist. The -p flag
    ## makes 'mkdir' create the parent directories as needed so
    ## you don't need to create $year explicitly.
    [[ ! -d "$BASE_DIR/$month/$day/$hour" ]] && mkdir -p "$BASE_DIR/$month/$day/$hour";

    ## Move the file
    mv "$file" "$BASE_DIR/$month/$day/$hour"
done

답변3

내 해결책은 다음과 같습니다.

#!/bin/bash

BASE_DIR="${1}"

if [ -z "${BASE_DIR}" ]; then
  BASE_DIR="/home/Work/LogFiles"
fi

if [ ! -d "${BASE_DIR}" ]; then
  echo "Error: '${BASE_DIR}' does not exists." >2
  exit 1
fi

declare -a MONTH_NAMES
MONTH_NAMES[1]='JAN'
MONTH_NAMES[2]='FEB'
MONTH_NAMES[3]='MAR'
MONTH_NAMES[4]='APR'
MONTH_NAMES[5]='MAY'
MONTH_NAMES[6]='JUN'
MONTH_NAMES[7]='JUL'
MONTH_NAMES[8]='AUG'
MONTH_NAMES[9]='SEP'
MONTH_NAMES[10]='OCT'
MONTH_NAMES[11]='NOV'
MONTH_NAMES[12]='DEC'


find "${BASE_DIR}" -maxdepth 1 -mtime +30 -type f -name '*.log' \
  | grep -e '/[0-9]*.log$' \
  | while read FILE; do

  FILENAME="$(basename "${FILE}")"

  FILE_YEAR="$(echo "${FILENAME}" | cut --bytes=1-4)"
  FILE_MONTH="$(echo "${FILENAME}" | cut --bytes=5-6)"

  FILE_MONTH_NAME="${MONTH_NAMES[${FILE_MONTH}]}"

  REPORT_DIR="${BASE_DIR}/${FILE_YEAR}/${FILE_MONTH_NAME}"
  test -d "${REPORT_DIR}" || mkdir -p "${REPORT_DIR}"

  mv "${FILE}" "${REPORT_DIR}"

  echo "'${FILENAME}' moved to '${REPORT_DIR}'"
done

관련 정보