Як я можу видалити пронумеровані файли в заданому діапазоні?


16

У мене folderAє деякі файли з послідовністю числа, починаючи з a_000000. Що я хочу зробити, це видалити файли, починаючи з певного числа: скажімо, a_000750до кінця файлів у цьому folderA. Не могли б хто-небудь порадити, як це зробити за допомогою сценарію оболонки?


Чи можу я припустити, що всі ці назви файлів мають 6-значні суфікси?
муру

так, вони є :) вони починають від a_000000 до деякої кількості
Tak

5
rm a_000[89]* a_0007[5-9]*?
Rinzwind

@Rinzwind, чи можете ви поясніть цю команду?
Так,

2
@ user1460166 a_000[89]*включає кожен файл, що починається з a_0008або a_0009, і a_0007[5-9]*включає кожен файл, що починається з, a_0007а потім містить число від 5 до 9, після чого слід що-небудь.
муру

Відповіді:


35

Якщо припустити, що ви знаєте або вгадаєте кінець діапазону, ви можете використовувати розширення дужок :

rm a_{000750..000850}

Вищесказане видалить 101 файл між a_000750 та a_000850 включно (та скаржиться на назви файлів, які посилаються на неіснуючі файли). Якщо у вас занадто багато файлів для цього, використовуйте find:

find . -name 'a_*' | while read file; do 
  [ "${file#./a_}" -gt 000749 ] && rm -v "$file" 
done

Тут findпросто перераховані всі файли, які відповідають a_*. Список передається в whileцикл, де кожне ім'я файлу читається в змінну $file. Потім, використовуючи функції маніпуляції з рядком bash , якщо числова частина (знайти файли, що друкують як ./file, таким чином ${file#./a_}друкує тільки число) 000750, файл видаляється. Це -vпросто там, щоб ви могли побачити, які файли було видалено.

Зауважте, що вище припускається розумні імена файлів. Якщо у ваших імен можуть бути пробіли, нові рядки або інші дивні символи, скористайтеся цим замість цього:

find . -name 'a_*' -print0 | while IFS= read -rd '' file; do 
  [ "${file#./a_}" -gt 000749 ] && rm -v "$file" 
done

Чому уникати [[?
muru

1
@muru навіщо це використовувати? Наприклад, [[не спрощує речі [[ "${file#./a_}" > 000749 ]], навіть не робить їх коротшими. Мені не подобається використовувати непотрібний синтаксис, і цей навіть буде працювати в більш простих оболонках, як dash.
тердон

Тому що [[краще справляється з просторами та дивацтвами (я ні про що не дбаю >).
муру

1
@muru так, але [це добре, якщо ви цитуєте змінну, як у мене, працює на набагато більше оболонок і простіше.
тердон

Якщо ти наполягаєш. Це не мої проблеми.
муру

3

Ви можете зробити щось подібне:

find . -regextype posix-extended -iregex './a_[0-9]{6}' -execdir bash -c '[[ ${1##./a_} > 000750 ]] && echo $1' "removing: " {} \;

Або:

find . -regextype posix-extended -iregex './a_[0-9]{6}' | sort | sed '0,/000750/d' | xargs echo

Перший метод передбачає фіксований префікс, знімає його та перевіряє значення.

Другий метод передбачає суфікс фіксованої довжини (і загальний фіксований префікс) і спирається на цей факт; і що, хоч і лексикографічно 201йде раніше 31, це не раніше 031.

Перевірте це за допомогою echoкоманди, і як тільки ви переконаєтесь, що в ній вказані правильні файли, використовуйте rmзамість цього.


ніхто з них не працює: /
Tak

@ user1460166 ах, це, мабуть, пов'язане з регулярними виразами. Я його оновлю.
муру

все ще не працює. btw, файли є .png :)
Так,

@ user1460166 Ви можете сказати, як це не працює?
муру

Я відкриваю термінал, CD в папку, потім копіюю рядок і вставляю його, але файли не видаляються
Tak

0

Рішення оболонки POSIX

Перше рішення тердона покладається на розширення брекетів , яке є властивістю, bashі ksh, однак, воно не може бути використане в стандартній /bin/shоболонці, з якою на Ubuntu посилається /bin/dash.

У випадках, коли вам доводиться покладатися /bin/shна портативність своїх сценаріїв, як правило, існує два способи наблизитись до цього. Одне було б через глобус. Просто cd folderAі звідти біжать rm a_*. Інший спосіб - реалізувати альтернативу циклу C-стилю для використання while <CONDITION>;do ...doneв мові оболонки та відформатувати числа за допомогою printf:

$ sh -c 'i=0;while [ $i -le 750 ]; do filename=$(printf "a_%06d" $i);echo "$filename";i=$((i+1)) ;done'

Зауважте, що тут я використовую echo. Замінити echo "$filename"з rm ./"$filename"або , rm -- "$filename"коли ви будете готові видалити файли. Також зауважте, що це потрібно зробити, коли ви вже cdввійшли в потрібний каталог.

(ab) з використанням awk

Будучи приємною мовою, схожою на C, може допомогти нам двома способами: (1) ми можемо генерувати назви файлів за допомогою циклу for-loop та форматувати їх за допомогою sprintfфункції, та (2) видаляти згадані файли за допомогою system()команди, яка передасть створене ім’я файлу та rmкоманду до /bin/sh:

awk 'BEGIN{for(i=0;i<=750;i++){filename=sprintf("a_%06d",i);system("rm "filename);} }'

Perl

Продовжуючи ідею портативного підходу, де ми "генеруємо" назви файлів, ми можемо зробити те ж саме в Perl:

perl -le 'for(0..750){$fd=sprintf("a_%06d",$_);unlink($fd)}'

0

Настільки ж просто

rm partialfilename* -f

У вашому прикладі це так

rm a_00075* -f

1
Вибачте, але це не діапазон, це всі файли, починаючи з a_00075...
Fabby

1
* - це підстановка, ОП шукає відповідь про те, як видалити RANGE з речей ... Наприклад, якщо у вас були файли від 1 до 100, і хотіли видалити # 41 до №75
Джошуа Беснеатте
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.