К сожалению, при сопоставлении с регулярным выражением 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