Shell-Skript bash: Datei verschieben, iterieren, basierend auf dem Monat

Shell-Skript bash: Datei verschieben, iterieren, basierend auf dem Monat

Ich habe sehr wenig Ahnung von Shell-Skripten, aber leider muss ich eines schreiben. Ich möchte nach Bash-Skript-Iterationen zum Verschieben von Dateien fragen. Ich muss Protokolldateien nach Monaten sortiert verschieben, die dann per Cronjob ausgeführt werden. Der Plan war, mtime +30 (1 Monat vorher)-Dateien in mehrere Ordner zu verschieben und den Cronjob täglich auszuführen, z. B.:

VOR

/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

NACH

/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

wobei ich keine Ahnung habe, welche Methoden ich verwenden musste. Also hier ist mein schreckliches Shell-Skript:

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

Und ja, der Fall $monthfunktioniert nicht mit der vorherigen For-Schleife $file. Warum? Ich weiß es nicht. Ich kopiere einfach aus verschiedenen Quellen, Foren, Beispiele in die For-Schleife und trotzdem funktioniert es nicht.

Antwort1

Erstens ist esnie eine gute Idee, die Ausgabe zu analysieren vonlsda dies zu allen möglichen Problemen führen kann. Eine bessere Möglichkeit, das Alter einer Datei zu ermitteln, ist stat. Zum Beispiel:

$ 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

Nun wissen wir, wie wir das Alter der Datei ermitteln können. Die Frage ist nun, wie wir es in einen dreistelligen Monatsnamen umwandeln können. Am einfachsten geht das mit date:

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

Die Kombination der beiden Befehle ergibt:

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

Unter Berücksichtigung dieser Tatsache können Sie Ihr Skript wie folgt schreiben:

#!/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

Das obige Skript geht davon aus, dass Sie das tatsächliche Änderungsdatum der Dateien erhalten und nicht den Namen analysieren möchten. Wenn Sie stattdessen den Namen analysieren möchten, lassen Sie es mich wissen und ich werde es entsprechend ändern.

Antwort2

Danke an terdon: Ich habe es geschafft, sein/ihr Skript zu nehmen und es so zu ändern, dass es unter OS X funktioniert. Ich habe auch die Ordnerstruktur so geändert, dass sie auf Monat, Tag und Stunde basiert:

#!/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

Antwort3

hier ist meine Lösung:

#!/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

verwandte Informationen