удалить самые старые файлы

9

Я пытаюсь удалить старые файлы из каталога и оставить только 3 новых файла.

cd /home/user1/test

while [ `ls -lAR | grep ^- | wc -l` < 3 ] ; do

    rm `ls -t1 /home/user/test | tail -1`
    echo " - - - "

done

что-то не так с условным утверждением.

d3vil0
источник

Ответы:

9

Если вы хотите зациклить файлы, никогда не используйтеls *. tl; dr Есть много ситуаций, когда вы в конечном итоге удалите не тот файл или даже все файлы.

Тем не менее, к сожалению, это сложно сделать прямо в Bash. Там в ответ работает над в виде дубликата вопроса моего даже старшеfind_date_sorted , которые вы можете использовать с небольшими изменениями:

counter=0
while IFS= read -r -d '' -u 9
do
    let ++counter
    if [[ counter -gt 3 ]]
    then
        path="${REPLY#* }" # Remove the modification time
        echo -e "$path" # Test
        # rm -v -- "$path" # Uncomment when you're sure it works
    fi
done 9< <(find . -mindepth 1 -type f -printf '%TY-%Tm-%TdT%TH:%TM:%TS %p\0' | sort -rz) # Find and sort by date, newest first

* Без обид, ребята - я тоже lsраньше пользовался. Но это действительно не безопасно.

Изменить: Новыйfind_date_sorted с юнит-тестами.

l0b0
источник
Я второй части о не разборе ls. Кроме того, сценарий аккуратный, но я думаю, что это можно сделать в один лайнер, позвольте мне проверить ...
Рахму
Ну, вы всегда можете сжать код Bash в одну строку, но вопрос в том, будет ли он читабельным :)
l0b0
2
Если я могу безжалостно украсть идею у @ Peter.O, попробуйте в ((++counter>3))качестве теста. Это очень лаконично. Что касается односложных: если краткость является проблемой, закройте код в функции, тогда не беспокойтесь об этом.
Сорпигал
@Sorpigal Опрятный ярлык
l0b0
5

Чтобы удалить все, кроме 3 самых новых файлов, используя глоб zsh, вы можете использовать Om(заглавная O) для сортировки файлов от самых старых до самых новых и нижний индекс, чтобы получить нужные файлы.

rm ./*(Om[1,-4])
#    | ||||  ` stop at the 4th to the last file (leaving out the 3 newest)
#    | |||` start with first file (oldest in this case)
#    | ||` subscript to pick one or a range of files
#    | |` look at modified time
#    | ` sort in descending order
#    ` start by looking at all files

Другие примеры:

# delete oldest file (both do the same thing)
rm ./*(Om[1])
rm ./*(om[-1])

# delete oldest two files
rm ./*(Om[1,2])

# delete everything but the oldest file
rm ./*(om[1,-2])
Марио Лопес
источник
5

Безусловно, самый простой способ - использовать zsh и его глобальные квалификаторы : Omсортировать по убыванию возраста (т. Е. Старшему первому) и [1,3]сохранять только первые три совпадения.

rm ./*(Om[1,3])

Смотрите также Как фильтровать глобус в zsh для большего количества примеров.

И прислушайтесь к совету l0b0 : ваш код ужасно сломается, если у вас есть имена файлов, которые содержат специальные символы оболочки.

Жиль "ТАК - перестань быть злым"
источник
Вау, вау, держи поезд, это действительно комплексное решение в 1 линию?
MetaGuru
2
@ Райан Это зш для тебя.
Жиль "ТАК - перестань быть злым"
1

Вы можете использовать следующую функцию, чтобы получить самый новый файл в каталоге:

newest_in() 
{ 
    local newest=$1

    for f;do [[ $f -nt $newest ]] && newest="$f"; done;

    printf '%s\n' "$newest"
}

Дайте ему другой набор файлов, исключая новейший файл после каждой итерации.

Совет: если вы храните исходный набор файлов в массиве с именем «$ {files [@]}», сохраните индекс самого нового найденного файла и unset 'files[index]'перед следующей итерацией.

Применение: newest_in [set of files/directories]

Пример вывода:

[rany$] newest_in ./*
foo.txt
[rany$]
Рани Албег Вайн
источник
-1

Во-первых, -Rопция рекурсии, что, вероятно, не то, что вам нужно - она ​​будет искать и во всех подкаталогах. Во-вторых, <оператор (если он не рассматривается как перенаправление) предназначен для сравнения строк. Вы, вероятно, хотите -lt. Пытаться:

while [ `ls -1A | grep ^- | wc -l` -lt 3 ]

Но я бы использовал найти здесь:

while [ `find . -maxdepth 1 -type f -print | wc -l` -lt 3 ]
Arcege
источник
Оба не удастся, если одно или несколько имен файлов содержат '$ \ n'.
Рани Албег Вайн
-1

Я знаю, что разобрать грехls , но как насчет этого:

find . -type f -maxdepth 1 | xargs ls -ltr | sed '1,3d' | awk '{print $9}' | xargs rm

Быстрый тест с 5 пустыми файлами:

$ >1
$ >2
$ >3
$ >4
$ >5
$ find . -type f -maxdepth 1 | xargs ls -lt | sed '1,3d' | awk '{print $9}' | xargs rm
$ ls -1
3
4
5
Рудольф Адамкович
источник
В этом случае произойдет сбой по двум причинам - синтаксический анализ lsвывода и использование findи xargsвместе в неправильном пути. Если вы объединяете, findи xargsя рекомендую вам использовать finds -print0и соответственно xargss -Oпараметры. Читайте об использовании Find для получения дополнительной информации о предмете. Вы также можете посмотреть и прочитать, почему Парсинг ls очень плох.
Рани Албег Вайн
-2

Этот однострочный делает все, что я думаю:

ls -t1 /home/user/test | tail -n +4 | xargs -I{} rm -- "{}"
залп
источник
ls - инструмент для интерактивного просмотра информации о файлах. Его вывод отформатирован для людей и будет вызывать ошибки в скриптах. Используйте шары или найдите вместо этого. Понять, почему: mywiki.wooledge.org/ParsingLs
Рани Албег Вайн
-2

Вот одно из решений:

rm /appserver/webapplogs/$(ls -t1 /appserver/webapplogs/|tail -1)
Бабак
источник
1
@bakbak ls - инструмент для интерактивного просмотра информации о файлах. Его вывод отформатирован для людей и будет вызывать ошибки в скриптах. Посмотрите здесь, чтобы понять, почему . Говоря конкретно о вашем ответе - этот ответ будет прерван, если один или несколько файлов содержат символ $ '\ n'. Кроме того, в Подстановке команд (т. Е. $ (...)) отсутствуют двойные кавычки, что поднимает еще одну важную тему - Разделение слов !
Рани Албег Вайн