Удалить все, кроме самых последних файлов X в Bash - PullRequest
130 голосов
/ 25 августа 2008

Есть ли простой способ в довольно стандартной среде UNIX с bash запустить команду для удаления всех, кроме самых последних X-файлов из каталога?

Чтобы привести чуть более конкретный пример, представьте себе, что какое-то задание cron записывает файл (скажем, файл журнала или резервную копию) в каталог каждый час. Я хотел бы иметь способ запустить еще одно задание cron, которое бы удаляло самые старые файлы в этом каталоге, пока их не станет меньше, скажем, 5.

И чтобы было ясно, присутствует только один файл, его никогда не следует удалять.

Ответы [ 17 ]

2 голосов
/ 21 ноября 2011

с зш

Если вы не заботитесь о существующих каталогах и у вас будет не более 999 файлов (выберите большее число, если хотите, или создайте цикл while).

[ 6 -le `ls *(.)|wc -l` ] && rm *(.om[6,999])

В *(.om[6,999]), . означает файлы, o означает порядок сортировки вверх, m означает дату изменения (укажите a для времени доступа или c для изменения индекса), [6,999] выбирает диапазон файлов, поэтому сначала не нужно 5.

1 голос
/ 03 октября 2018

Мне требовалось элегантное решение для busybox (маршрутизатора), все решения xargs или array были для меня бесполезны - такой команды там не было. find и mtime не правильный ответ, так как речь идет о 10 пунктах и ​​не обязательно 10 днях. Ответ Эспо был самым коротким и чистым и, вероятно, самым неожиданным.

Ошибка с пробелами и когда файлы не должны быть удалены, просто решаются стандартным способом:

rm "$(ls -td *.tar | awk 'NR>7')" 2>&-

Немного больше образовательной версии: мы можем сделать все, если мы будем использовать awk по-другому. Обычно я использую этот метод для передачи (возврата) переменных из awk в sh. Поскольку мы все время читаем, что не может быть сделано, я позволю себе не согласиться: вот метод.

Пример для файлов .tar без проблем с пробелами в имени файла. Чтобы проверить, замените «rm» на «ls».

eval $(ls -td *.tar | awk 'NR>7 { print "rm \"" $0 "\""}')

Пояснение:

ls -td *.tar перечисляет все файлы .tar, отсортированные по времени. Чтобы применить ко всем файлам в текущей папке, удалите часть "d * .tar"

awk 'NR>7... пропускает первые 7 строк

print "rm \"" $0 "\"" создает строку: rm "имя файла"

eval выполняет его

Поскольку мы используем rm, я бы не использовал вышеуказанную команду в скрипте! Более мудрое использование:

(cd /FolderToDeleteWithin && eval $(ls -td *.tar | awk 'NR>7 { print "rm \"" $0 "\""}'))

В случае использования ls -t команда не нанесет никакого вреда таким глупым примерам, как: touch 'foo " bar' и touch 'hello * world'. Не то чтобы мы когда-либо создавали файлы с такими именами в реальной жизни!

Sidenote. Если бы мы хотели передать переменную в sh таким образом, мы бы просто изменили вывод (простая форма, без пробелов):

print "VarName="$1

для установки переменной VarName в значение $1. Несколько переменных могут быть созданы за один раз. Этот VarName становится нормальной переменной sh и впоследствии может быть использован в скрипте или оболочке. Итак, чтобы создать переменные с помощью awk и вернуть их обратно в оболочку:

eval $(ls -td *.tar | awk 'NR>7 { print "VarName=\""$1"\""  }'); echo "$VarName"
1 голос
/ 29 мая 2017

Удаляет все файлы, кроме 10 последних (большинство последних)

ls -t1 | head -n $(echo $(ls -1 | wc -l) - 10 | bc) | xargs rm

Если менее 10 файлов, файл не будет удален, и вы получите: заголовок ошибки: неверное количество строк - 0

Для подсчета файлов с помощью bash

1 голос
/ 02 сентября 2016

нашел интересный cmd в Sed-Onliners - удалите последние 3 строки - и он идеально подходит для другого способа кожи кошки (ладно, нет), но идея:

 #!/bin/bash
 # sed cmd chng #2 to value file wish to retain

 cd /opt/depot 

 ls -1 MyMintFiles*.zip > BigList
 sed -n -e :a -e '1,2!{P;N;D;};N;ba' BigList > DeList

 for i in `cat DeList` 
 do 
 echo "Deleted $i" 
 rm -f $i  
 #echo "File(s) gonzo " 
 #read junk 
 done 
 exit 0
0 голосов
/ 03 февраля 2016

Я превратил это в скрипт оболочки bash. Использование: keep NUM DIR, где NUM - это количество файлов для хранения, а DIR - каталог для очистки.

#!/bin/bash
# Keep last N files by date.
# Usage: keep NUMBER DIRECTORY
echo ""
if [ $# -lt 2 ]; then
    echo "Usage: $0 NUMFILES DIR"
    echo "Keep last N newest files."
    exit 1
fi
if [ ! -e $2 ]; then
    echo "ERROR: directory '$1' does not exist"
    exit 1
fi
if [ ! -d $2 ]; then
    echo "ERROR: '$1' is not a directory"
    exit 1
fi
pushd $2 > /dev/null
ls -tp | grep -v '/' | tail -n +"$1" | xargs -I {} rm -- {}
popd > /dev/null
echo "Done. Kept $1 most recent files in $2."
ls $2|wc -l
0 голосов
/ 07 июня 2013
leaveCount=5
fileCount=$(ls -1 *.log | wc -l)
tailCount=$((fileCount - leaveCount))

# avoid negative tail argument
[[ $tailCount < 0 ]] && tailCount=0

ls -t *.log | tail -$tailCount | xargs rm -f
0 голосов
/ 02 февраля 2010

Работает на Debian (предположим, то же самое на других дистрибутивах, которые я получаю: rm: не может удалить каталог `.. '

что довольно раздражает ..

Во всяком случае, я поправил вышеупомянутое, а также добавил grep в команду. В моем случае у меня есть 6 файлов резервных копий в каталоге, например. file1.tar file2.tar file3.tar и т. д., и я хочу удалить только самый старый файл (удалите первый файл в моем случае)

Сценарий, который я запустил для удаления самого старого файла, был:

ls -C1 -t | grep файл | awk 'NR> 5' | xargs rm

Это (как указано выше) удаляет первый из моих файлов, например file1.tar это также оставляет быть с file2 file3 file4 file5 и file6

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...