Wie kann ich nummerierte Dateien in einem bestimmten Bereich löschen?


16

Ich habe folderAdas hat einige Dateien mit einer Nummernfolge beginnend mit a_000000. Was ich tun möchte, ist, Dateien ab einer bestimmten Nummer zu löschen: Sagen wir, a_000750bis zum Ende der Dateien in dieser folderA. Könnte jemand bitte beraten, wie dies mit Shell-Skript zu tun ist?


Kann ich davon ausgehen, dass alle diese Dateinamen sechsstellige Suffixe haben?
muru

Ja, sie sind :) Sie starten von a_000000 bis zu einer bestimmten Zahl
Tak

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

@Rinzwind könntest du bitte diesen Befehl erklären?
Tak

2
@ user1460166 a_000[89]*enthält jede Datei, die mit a_0008oder beginnt a_0009, und a_0007[5-9]*enthält jede Datei, die mit a_0007und dann mit einer Zahl zwischen 5 und 9 beginnt , gefolgt von einer beliebigen Zahl.
Muru

Antworten:


35

Vorausgesetzt, Sie kennen das Ende des Bereichs oder können es erraten, könnten Sie Klammererweiterungen verwenden :

rm a_{000750..000850}

Mit dem obigen Befehl werden die 101 Dateien zwischen a_000750 und a_000850 einschließlich gelöscht (und es werden Dateinamen beanstandet, die auf nicht vorhandene Dateien verweisen). Wenn Sie zu viele Dateien dafür haben, verwenden Sie find:

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

Hier werden findeinfach alle passenden Dateien aufgelistet a_*. Die Liste wird an eine whileSchleife übergeben, in der jeder Dateiname in die Variable eingelesen wird $file. Wenn der numerische Teil (Find druckt Dateien als , druckt also nur die Zahl) oder größer ist, wird die Datei mithilfe der Zeichenfolgenmanipulationsfunktionen von bash gelöscht. Das ist einfach da, damit Sie sehen können, welche Dateien entfernt wurden../file${file#./a_}000750-v

Beachten Sie, dass das oben Gesagte Dateinamen voraussetzt. Wenn Ihre Namen Leerzeichen, Zeilenumbrüche oder andere seltsame Zeichen enthalten können, verwenden Sie stattdessen Folgendes:

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

Warum vermeiden [[?
muru

1
@muru warum es verwenden? [[Vereinfacht hier [[ "${file#./a_}" > 000749 ]]zum Beispiel nicht, verkürzt es auch nicht. Ich verwende keine unnötige Syntax und diese funktioniert sogar in einfacheren Shells wie dash.
Terdon

Weil [[ich mit Leerzeichen und Verrücktheiten besser umgehen kann (ich mag auch nicht viel >).
muru

1
@muru ja, aber [ist in Ordnung, wenn Sie die Variable wie ich zitieren, funktioniert auf weit mehr Shells und ist einfacher.
Terdon

Wenn du darauf bestehst. Nicht mein Problem.
muru

3

Sie könnten so etwas tun:

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

Oder:

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

Die erste Methode nimmt ein festes Präfix an, entfernt es und überprüft den Wert.

Die zweite Methode setzt ein Suffix fester Länge (und ein gemeinsames festes Präfix) voraus und stützt sich auf diese Tatsache. und das, während es in lexikographischer 201Hinsicht vorher kommt, vorher 31nicht 031.

Testen Sie dies mit dem echoBefehl, und verwenden Sie rmstattdessen , wenn Sie sicher sind, dass die richtigen Dateien aufgeführt sind .


keiner von ihnen arbeitet: /
Tak

@ user1460166 ah, das liegt wahrscheinlich an der Regex-Übereinstimmung. Ich werde es aktualisieren.
Muru

funktioniert immer noch nicht Übrigens sind die Dateien .png :)
Tak

@ user1460166 kannst du sagen, wie es nicht funktioniert?
Muru

Ich öffne das Terminal, CD in den Ordner, kopiere deine Zeile und füge sie ein, aber die Dateien werden nicht gelöscht
Tak

0

POSIX-Shell-Lösung

Die erste Lösung von terdon basiert auf der Klammererweiterung , die eine Eigenschaft von ist bashund kshjedoch nicht in der Standard- /bin/shShell verwendet werden kann, mit der Ubuntu verknüpft ist /bin/dash.

In Fällen, in denen Sie sich auf die /bin/shPortabilität Ihrer Skripte verlassen müssen, gibt es im Allgemeinen zwei Möglichkeiten, um dies zu erreichen. Man würde über Globbing sein. Gerade cd folderAund von dort laufen rm a_*. Die andere Möglichkeit wäre die Implementierung einer C-ähnlichen for-Loop-Alternative while <CONDITION>;do ...donein der Shell-Sprache und das Formatieren der Zahlen mit printf:

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

Beachten Sie, dass ich hier verwende echo. Ersetzen Sie echo "$filename"durch rm ./"$filename"oder, rm -- "$filename"wenn Sie bereit sind, die Dateien zu löschen. Beachten Sie auch, dass dies durchgeführt werden sollte, wenn Sie sich bereits cdin dem gewünschten Verzeichnis angemeldet haben.

(ab) awk benutzen

Awk, eine nette C-ähnliche Sprache, kann uns auf zwei Arten helfen: (1) Wir können Dateinamen mit for-loop generieren und sie über die sprintfFunktion formatieren und (2) die Dateien über einen system()Befehl löschen , der unseren generierten Dateinamen und rmBefehl übergibt zu /bin/sh:

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

Perl

Weiter mit der Idee des portablen Ansatzes, bei dem wir Dateinamen "generieren", können wir dasselbe in Perl tun:

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

0

So einfach wie

rm partialfilename* -f

In deinem Beispiel ist es

rm a_00075* -f

1
Tut mir leid zu sagen, aber das ist kein Bereich, das sind alle Dateien, die mit a_00075... beginnen
Fabby

1
* ist ein Platzhalter, OP sucht nach einer Antwort zum Löschen einer Reihe von Dingen ... z. B. wenn Sie die Dateien 1 bis 100 hatten und # 41 bis # 75 löschen wollten
Joshua Besneatte
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.