Переместить файлы в правильные каталоги даты на основе имени файла - PullRequest
0 голосов
/ 23 июня 2018

Некоторые из моих файлов находятся в неправильных каталогах, и я пытаюсь переместить их в правильное местоположение.

пример:

каталог 20180622 будет содержать только имена файлов с 20180622 в имени

если каталог 20180622 содержит файл с именем 20180623, то это неуместный файл, и он должен перейти в соответствующий правильный каталог, а именно 20180623 фиксированная структура каталогов (к счастью)

date1/a/b/someprefix.date1.somesuffix #no problem
date1/a/b/someprefix.date2.somesuffix # problem
date2/c/d/someprefix.date2.somesuffix # no problem
date2/e/f/someprefix.date3.somesuffix # problem

date1/a/b/someprefix.date1.somesuffix
date2/a/b/someprefix.date2.somesuffix # problem fixed
date2/c/d/someprefix.date2.somesuffix
date3/e/f/someprefix.date3.somesuffix #problem fixed

используя find . -type f я получаю список всех файлов, но не получаю, как mv файлы исправить. someprefix может быть чем угодно (может содержать также точку, так что вырезка не является хорошим способом извлечь дату из имени файла) $f =~ (.*)(201[5-8][0-9][0-9][0-9][0-9][0-9])(.*) - это то, что я пытаюсь получить дату, извлеченную из имени файла

Ответы [ 2 ]

0 голосов
/ 23 июня 2018

К сожалению, при сопоставлении с регулярным выражением bash вы не можете извлечь все подспряжения, поэтому я прибегаю к grep, чтобы найти все даты.

find . -type f -print0 |
  while IFS= read -d "" -r filename; do
    mapfile -t dates < <(echo "$filename" | grep -Eo '\<201[5-8][0-9]{4}\>')
    if [[ ${#dates[@]} -eq 2 ]] && [[ ${dates[0]} != ${dates[1]} ]]; then
      destdir=$(dirname "$filename" | sed "s/${dates[0]}/${dates[1]}/")
      mkdir -p "$destdir"
      mv -v "$filename" "$destdir"
    fi
  done

Тестирование:

$ tree
.
├── 20180621
│   └── a
│       └── b
│           ├── a.20180621.txt
│           └── foo.20180701.bar
└── 20180701
    └── c
        └── d
            └── ok.20180701

6 directories, 3 files

У нас есть один файл, который нужно переместить

$ find . -type f -print0 |
   while IFS= read -d "" -r filename; do
     mapfile -t dates < <(echo "$filename" | grep -Eo '\<201[5-8][0-9]{4}\>')
     if [[ ${#dates[@]} -eq 2 ]] && [[ ${dates[0]} != ${dates[1]} ]]; then
       destdir=$(dirname "$filename" | sed "s/${dates[0]}/${dates[1]}/")
       mkdir -p "$destdir"
       mv -v "$filename" "$destdir"
     fi
   done
'./20180621/a/b/foo.20180701.bar' -> './20180701/a/b/foo.20180701.bar'

и результат

$ tree
.
├── 20180621
│   └── a
│       └── b
│           └── a.20180621.txt
└── 20180701
    ├── a
    │   └── b
    │       └── foo.20180701.bar
    └── c
        └── d
            └── ok.20180701

8 directories, 3 files

Не полагаясь на grep, и это поправка к ответу Арунта:

find 20+([0-9])/ -type f -print0 |
    while IFS= read -d "" -r filename; do
        dirdate=${filename%%/*}
        if [[ "$(basename "$filename")" =~ 20[0-9]{6} ]]; then
            filedate=${BASH_REMATCH[0]}
            if [[ $dirdate != $filedate ]]; then
                dest=${filename/$dirdate/$filedate}
                echo mkdir -p "$(dirname "$dest")"
                echo mv -v "$filename" "$dest"
            fi
        fi
    done
0 голосов
/ 23 июня 2018

Это должно быть довольно легко обрабатывать, вам просто нужен цикл и оператор if.

for path in $(find . -type f); do
    dirdate=$(echo $path | cut -d '/' -f 2)
    filedate=$(basename $path | cut -d '.' -f 2)

    if [[ $dirdate != $filedate ]]; then
        mv $path $(dirname $path | sed "s/$dirdate/$filedate/g")
    fi
done

Идея здесь предельно проста: он зацикливается в файлах, получая полный путь к файлу (./date1/a/b/prefix.date.suffix)и проверьте, равен ли date1 date.Если это не так, переместите файл в тот же путь, где date1 был заменен на date.

Редактировать для комментариев

Если вы хотите обработать несколько файлов для удаления ваших имен файлов, вам просто нужноизмените строку filedate= следующим образом:

filedate=$(basename $path | awk -F'[._\-]' '{print $2}' 2> /dev/null)

Это немного сложнее, но, скажем, это Bash.

2> /dev/null, чтобы заставить awk предупреждать молчание.

...