Kabuk betiği bash: Aya göre dosya yinelemeyi taşıma


1

Shell betikleri hakkında çok az bilgim var, fakat ne yazık ki bir tane yazmak zorundayım. Bash script yineleme hareketli dosyalar hakkında sormak istiyorum, cronjob tarafından yürütülecek aya göre sıralanmış günlük dosyalarını taşımak gerekiyor. Plan mtime +30 (1 ay önce) dosyalarını birkaç klasöre taşımaktı ve cronjob günlük olarak çalıştırılacaktı.

ÖNCE

/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

SONRA

/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

ki kullanmam gereken yöntemler hakkında hiçbir ipucu bulamadım. İşte benim korkunç kabuk betiğim:

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

Ve evet, dava $monthönceki döngü için işe yaramaz $file. Niye ya? Bilmiyorum. Sadece çeşitli kaynaklardan, forumlardan, döngü için örneklerden kopyalarım ve henüz işe yaramıyor.


Tarihini dosyanın adından almak mı yoksa dosyaları gerçek değişiklik tarihini kullanmak mı istiyorsun?
terdon

Dosyadan tarih almak niyetindeydim, evet
demeyi

Yanıtlar:


7

Her şeyden önce, her türlü soruna yol açabileceğinden , çıktısını ayrıştırmak asla iyi bir fikir değildirls . Bir dosyanın yaşını almak için daha iyi bir yoldur stat. Örneğin:

$ 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

Şimdi, dosyanın yaşını nasıl alacağımızı biliyoruz. Soru, bunu üç harfli bir ay adına dönüştürmektir. En kolay kullanımdır date:

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

İki komutu birleştirmek:

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

Bu nedenle, bunu aklınızda tutarak, komut dosyanızı şu şekilde yazabilirsiniz:

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

Yukarıdaki betiğin adı, ayrıştırma değil, dosyaların gerçek değişiklik tarihini almak istediğinizi varsayar. Eğer adı ayrıştırmak istiyorsan bunun yerine bana haber ver, ben de buna göre değiştireyim.


Evet!! muazzam iş! Bitti! Yardımın için minnettarım. Çok teşekkür ederim! Bu tamamen
umduğum gibi

Fotoğraflarımı tarihli klasörlere ayıran bir komut dosyası yapmak için bu örneği kullandım, ancak şunu kullanmam gerekiyor: year = $ (tarih -d "$ (stat -c% y" $ file ")" +% Y) (notu msgstr "" $ $ dosya etrafında) çünkü boşluklu dosyalar taşıyordu. Bu kesme işareti diğer kesme işareti içinde mi? Yoksa bunu farklı bir şekilde mi yapmalıyım?
timhc22

1
@ unegma hayır, ilk etapta alıntı gerekirdi. İşaret ettiğiniz için teşekkürler, yanıtı düzenlendi.
terdon

Bu çok kafa karıştırıcı. terdon'un cevabı düzenlediği düzenleme, timhc22'nin doğrudan yukarıdaki yorumunda yer almayan fazladan bir alıntı tırnak kümesine sahiptir. Ve ben bunu OS X'te yapmaya çalışıyorum, ancak doğrudan bunu cevapladığımı iddia eden cevap, ikisinden de tamamen farklı alıntılar yapıyor ve içinde boşluk bulunan dosya yollarında kopuyor.
John Smith,

@MichaelKupietz, cevabımdan alıntılama yaklaşımını, diğerinden ise stat komutlarını kullanıyor. OSX bayrağı datedesteklemiyor -d. Yani, örneğinmonth="$(stat -f '%Sm' -t '%m' "$file")"
terdon

2

Terdon sayesinde: Senaryonun senaryosunu almayı ve onu değiştirmeyi OS X'de çalışması için değiştirdim. Klasör yapısını da ay, gün ve saat olarak değiştirdim:

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

Bu, içinde herhangi bir yerde boşluk bulunan dosya yolları için kopar.
John Smith,

@MichaelKupietz Burada alıntıyı düzelttim, güncellenmiş sürümü deneyin, herhangi bir dosya adı için çalışması gerekir.
terdon

0

İşte benim çözüm:

#!/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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.