ubuntuusers.de

alle Dateien im Verzeichnis löschen die nicht xy enthalten

Status: Gelöst | Ubuntu-Version: Ubuntu 16.04 (Xenial Xerus)
Antworten |

delmic

Anmeldungsdatum:
12. März 2010

Beiträge: 116

Wohnort: Grafenrheinfeld

Hallo, gibt es eine einfache Möglichkeit den Löschbefehl zu negieren? Ich möchte alle Dateien eines Verzeichnisses löschen außer denen die ein v vor dem . enthalten also einfach rm *v.* nur sollen genau diese nicht gelöscht werden. 😀 Vielen Dank

Bearbeitet von ChickenLipsRfun2eat:

Bitte halte dich an die Forensyntax und verwende den Codeblock nur für Code!

Moderiert von Taomon:

Schieb nach Shellzeugs.

ChickenLipsRfun2eat Team-Icon

Anmeldungsdatum:
6. Dezember 2009

Beiträge: 12067

Ich würde das über find lösen.

Beispiel:

1
find . -type f -not -iname "*v.*" -ls

apt-ghetto

Anmeldungsdatum:
3. Juni 2014

Beiträge: 2943

Mit der Bash könnte dies eventuell so gehen

1
2
3
4
5
6
7
8
# extglob aktivieren
shopt -s extglob

# Falls es funktioniert, "echo" entfernen
echo rm !(*v.*)

# und extglob wieder deaktivieren
shopt -u extglob 

seahawk1986

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11260

Wohnort: München

Reicht da nicht sowas (das -i kann man natürlich weglassen, wenn man sich davon überzeugt hat, dass der Befehl das tut was man will)?

rm -i *[!v].* 

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13204

seahawk1986 schrieb:

Reicht da nicht sowas (das -i kann man natürlich weglassen, wenn man sich davon überzeugt hat, dass der Befehl das tut was man will)?

rm -i *[!v].* 

Nein, denn das findet die falschen Dateien:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
$ for pre in '' a; do for post in '' b; do for f in v v. .v .; do touch "$pre$f$post"; done
> done; done
$ ls -1
a
a.
a.b
av
a.v
av.
avb
a.vb
av.b
b.
v
v.
vb
v.b
$ echo rm -i *[!v].*
rm -i a. a.b a.v a.vb b.

Es werden einige Dateien nicht gelöscht, die aber gelöscht werden sollten (z.B. "a", "av"). Das liegt daran, dass Dein Suchmuster zwingend einen Punkt erfordert - aber das ist etwas anderes als "alle Dateien, die nicht 'v.' enthalten". Die anderen beiden Lösungen:

1
2
3
4
$ find . -type f \! -iname '*v.*' -exec basename {} \; | paste -sd ' '
av a.b a .b .vb .v vb .c b. avb a.v a. a.vb v
$ echo !(*v.*)
a a. a.b av a.v avb a.vb b. v vb

Das richtige Ergebnis liefert nur die Lösung mit find:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
$ diff -U3 <(find . -type f \! -iname '*v.*' -exec basename {} \; | sort) <(printf '%s\n' !(*v.*) | sort)
--- /dev/fd/63	2017-12-06 12:52:46.706136316 +0100
+++ /dev/fd/62	2017-12-06 12:52:46.710136400 +0100
@@ -5,10 +5,6 @@
 a.v
 avb
 a.vb
-.b
 b.
-.c
 v
-.v
 vb
-.vb

So testet man das strukturiert. ☺

delmic

(Themenstarter)

Anmeldungsdatum:
12. März 2010

Beiträge: 116

Wohnort: Grafenrheinfeld

Vielen Dank für die Vorschläge.

1
rm *[!v].*

Passt schon für mich. Ich habe das ! bei rm nicht gefunden wusste eben auch nicht ob man das einfach so negieren kann. Einfachste Lösung.

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13204

delmic schrieb:

Vielen Dank für die Vorschläge.

1
rm *[!v].*

Passt schon für mich.

Da implementiert allerdings nicht die Regel, die Du im ersten Posting gegeben hast.

Ich habe das ! bei rm nicht gefunden wusste eben auch nicht ob man das einfach so negieren kann.

Das hat auch nix mit rm zu tun. Das Globbing (Filename Expansion) macht die Shell.

Einfachste Lösung.

Naja, ich finde dieses auch nicht sehr einfach:

1
find -type f \! -iname '*v.*' -delete

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

Um das Ganze noch mal systematisch zu betrachten: es geht hier um die Filename Expansion der Shell, ganz unabhängig von rm oder welchem Befehl auch immer.

Gucken wir also mal, wie das Muster für die Shell aussehen müsste:

  1. Das was Du behalten möchtest, sind die Dateien nach dem Muster *v.* - ok.

  2. Nun kann die Shell das Muster genau umkehren (→ der letzte Eintrag unter Pattern Matching):

    1
    2
    3
    4
    5
    6
    n=0
    for f in !(*v.*) ; do
        echo "$f"
        ((n++))
    done
    echo $n
    

    sollte Dir die korrekte Liste auswerfen.
    (→ die Zahl der Treffer dieser beiden Muster sollte die Gesamtzahl der Dateien ergeben - sonst ist da was faul !)

  3. Wahrscheinlich wird man das gewünschte Muster auch noch anders bauen können, aber bestimmt nicht einfacher.

LG,

track

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13204

track schrieb:

Gucken wir also mal, wie das Muster für die Shell aussehen müsste:

  1. Das was Du behalten möchtest, sind die Dateien nach dem Muster *v.* - ok.

  2. Nun kann die Shell das Muster genau umkehren (→ der letzte Eintrag unter Pattern Matching):

    1
    2
    3
    4
    5
    6
    n=0
    for f in !(*v.*) ; do
        echo "$f"
        ((n++))
    done
    echo $n
    

    sollte Dir die korrekte Liste auswerfen.

Tut sie aber nicht (s.o.). Oder entdeckst Du einen Fehler in meinem Test?

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

Hm ... wenn ich jetzt mal meinen Vorschlag, und Dein Globbing-Muster auf mein Home-Verzeichnis loslasse, bekommen ich folgendes:

track@track:~$ n=0;
track@track:~$ for f in *v.* ; do      ((n++)); done           # Dateien mit "v." drin
track@track:~$ echo $n
5
track@track:~$ n=0
track@track:~$ for f in !(*v.*) ; do   ((n++)); done            # mein Muster:
track@track:~$ echo $n
754
track@track:~$ n=0;
track@track:~$ for f in * ; do         ((n++)); done            # bezieht sich auf alle Dateinamen
track@track:~$ echo $n                                          # (einschliesslich solcher, wo gar kein Punkt drin vorkommt)
759
track@track:~$ n=0;
track@track:~$ for f in *[!v].* ; do   ((n++)); done            # Dein Muster:
track@track:~$ echo $n
622
track@track:~$ n=0;
track@track:~$ for f in *.* ; do   ((n++)); done                # bezieht sich offensichtlich nur auf solche mit einem Punkt drin
track@track:~$ echo $n
627 

Zum Vergleich mal Dein find-Befehl:

track@track:~$ find -maxdepth 1 -type f  -iname '*v.*' -printf "x\n" | wc
      5       5      10
track@track:~$ find -maxdepth 1 -type f \! -iname '*v.*' -printf "x\n" | wc
    764     764    1528
track@track:~$ find -maxdepth 1 -type f   -printf "x\n" | wc
    769     769    1538
track@track:~$ ls -b1 | wc
    759     843   13004 

- bezieht sich offensichtlich auch auf alle Dateinamen (einschliesslich der, die gar keinen Punkt enthalten),
findet aber noch ± 10 Treffer mehr - allerdings habe ich keine Ahnung, woher die kommen könnten.**

Mich beruhigt allerdings, dass ls genau so viele Treffer anzeigt wie mein Muster ...
So far ...

LG,

track

** Edit:
So - jetzt habe ich die Listen mal geloggt und mit meld verglichen:
Der Unterschied ist der, dass in Deiner find-Liste auch alle versteckten Dateien mit drin stehen (aber keine Verzeichnisnamen !), während die Filename Expansion auch alle Verzeichnisnamen mit liefert (aber keine versteckten Dateien !).

Tja, Pest oder Cholera: man muss wohl in beiden Fällen mal gucken, was man braucht, bzw. wie man die unerwünschten Irrläufer ausblendet ... 😉 😀

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13204

Ich würde ja lieber find verwenden, weil das einfach mehr Kontrolle erlaubt - selbst, wenn man die Tiefe mit "-maxdepth 1" begrenzt. Das Glob-Muster unterscheidet ja auch nicht zwischen Dateien und Ordnern, wie Du richtig bemerkt hast. Also, das ist mein Favorit für die ursprüngliche Aufgabenstellung:

1
find -type f \! -iname '*v.*' -delete

ChickenLipsRfun2eat Team-Icon

Anmeldungsdatum:
6. Dezember 2009

Beiträge: 12067

Zudem bring iname case-insensitivity mit sich, die for f in *v.*-Methode müsste also mit [V|v] ergänzt werden, oder die find-Methode mit name statt iname aufgerufen werden, oder?

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13204

ChickenLipsRfun2eat schrieb:

Zudem bring iname case-insensitivity mit sich, die for f in *v.*-Methode müsste also mit [V|v]

Ohne das Pipe-Symbol:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
$ ls -1
|a
v.
V.
va
Va
$ printf '%s\n' [vV]*
v.
V.
va
Va
$ printf '%s\n' [v\|V]*
|a
v.
V.
va
Va

ergänzt werden, oder die find-Methode mit name statt iname aufgerufen werden, oder?

Genau.

Antworten |