Я хотел бы узнать все файлы размером более 100 Мб, к которым не было доступа в течение последнего месяца, и я успешно написал:
find / -size +100M -atime +30
И теперь я хочу переместить эти файлы в папку с именем /big-not-used, изменив ее имя следующим образом: file_nameYYYYMMDD
где file_name — это имя исходного файла, а YYYYMMDD — это сегодняшняя дата в формате год месяц день. Например, film.mkv
идет в/big-not-used/film.mkv20161031
Мое предложение было бы таким:
find / -size +100M -atime +30 -exec mv {} /big-not-used/... \;
Но я не знаю, как добавить сегодняшнюю дату к имени файла. Я обнаружил, что date +%Y-%m-%d
выводит: 2016-10-31
что полезно. Теперь возникает вопрос, как получить имя этого файла? Следующее:
https://stackoverflow.com/questions/5456120/how-to-only-get-file-name-with-linux-find
... -exec basename {} \;
Может быть?:
find / -size +100M -atime +30 -exec mv {} /big-not-used/$(basename {})$(date +%Y-%m-%d) \;
Но он выдает ошибку, потому что basename отвечает полным путем к файлу вместо его имени, которое я бы использовал:
${var##/*/}
чтобы получить имя файла, но вопрос в том, как мне вставить то, что basename {}
отвечает, в переменную var в предыдущем выражении!?.
Может быть?
$(${$(basename {})##/*/})
Но это говорит о синтаксической ошибке возле неожиданного '}'...
решение1
Вы были близки к:
find / -size +100M -atime +30 \
-exec mv {} /big-not-used/$(basename {})$(date +%Y-%m-%d) \;
$(...)
Но без кавычек происходит расширение оболочки конструкцийперед find
выполнением команды. Другими словами, учитывая приведенную выше командную строку, которая на самом деле будет выполнена, это:
find / -size +100M -atime +30 \
-exec mv {} /big-not-used/{}2016-10-30 \;
Потому что результат $(basename {})
— это просто {}
, и вот почему вы получаете полный путь. Попробуйте это вместо этого:
find / -size +100M -atime +30 \
-exec sh -c 'mv {} /tmp/big-not-used/$(basename {})$(date +%Y-%m-%d)' \;
Для проверки вы можете заменить mv
на echo mv
, например так:
find / -size +100M -atime +30 \
-exec sh -c 'echo mv {} /tmp/big-not-used/$(basename {})$(date +%Y-%m-%d)' \;
...и посмотрите, как выглядят сгенерированные команды.
решение2
Я немного улучшил решение Ларка, чтобы сделать только один sh
вызов:
find / -size +100M -atime +30 -exec sh -c \
'for f do mv "$f" /tmp/big-not-used/"$(basename "$f")$(date +%Y-%m-%d)"; done' sh {} +
Либо sh
вообще без звонков:
while IFS= read -r f; do
mv "$f" /tmp/big-not-used/"$(basename "$f")$(date +%Y-%m-%d)"
done < <(find / -size +100M -atime +30)
(Последнее при условии, что в именах файлов нет символов новой строки.)
Для отладки вам может понадобиться добавить -v
( mv
если поддерживается).