видалити найстаріші файли


9

Я намагаюся видалити старі файли з каталогу та залишити лише три новіші файли.

cd /home/user1/test

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

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

done

щось не в порядку із умовним твердженням.

Відповіді:


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 з одиничними тестами.


Другу частину про несинтаксичний розбір ls. Також сценарій акуратний, але я думаю, що це можна зробити в одному вкладиші, дозвольте мені перевірити ...
rahmu

Що ж, ви завжди зможете компактний код Bash в одноколірці, але питання полягає в тому, чи він буде читабельний :)
l0b0

2
Якщо я можу нещадно вкрасти ідею від @ Peter.O, спробуйте ((++counter>3))як ваш тест. Це приємно лаконічно. Що стосується oneliners: Якщо стислість - це питання, загорніть код у функцію, тоді не турбуйтеся про це.
Сорпігал

@Sorpigal Акуратний ярлик
l0b0

5

Щоб видалити всі, крім трьох найновіших файлів, за допомогою zsh glob, ви можете використовувати 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


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 ]

І те й інше не вдасться, якщо одне або більше імен файлів містять '$ \ n'.
Rany Albeg Wein

-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 для отримання додаткової інформації про цю тему. Ви також можете поглянути і почитати про те, чому Парсінг Лс дуже поганий.
Rany Albeg Wein

-2

Цей одноколісний робить все, що я думаю:

ls -t1 /home/user/test | tail -n +4 | xargs -I{} rm -- "{}"

ls - це інструмент для інтерактивного перегляду інформації про файли. Його вихід відформатований для людей і призведе до помилок у сценаріях. Використовуйте глобуси або знаходьте замість цього. Зрозумійте, чому: mywiki.wooledge.org/ParsingLs
Rany Albeg Wein

-2

Ось одне рішення:

rm /appserver/webapplogs/$(ls -t1 /appserver/webapplogs/|tail -1)

1
@bakbak ls - це інструмент для інтерактивного перегляду інформації про файли. Його вихід відформатований для людей і призведе до помилок у сценаріях. Подивіться тут, щоб зрозуміти, чому . Конкретно кажучи про вашу відповідь - ця ламається, якщо один або кілька файлів містять символ $ '\ n'. Крім того, у Command Substitution (тобто $ (...)) бракує подвійних лапок, що піднімає ще одну важливу тему - Розщеплення слів !
Rany Albeg Wein
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.