kruppka
Anmeldungsdatum: 22. Januar 2006
Beiträge: 161
|
Hallo zusammen, ich habe hier ein Verzeichnis mit zahlreichen Unterordnern. Diese Unterordner haben Nummern (die manchmal ihrerseits Unterordner allerdings ohne Nummer haben). Die Verzeichnisnamen lauten nach dem Schema Name_xy (Zahl_immer_vierstellig) gesuchte_Zahl_auch_immer_vierstellig eventuell_Rest_aus_Buchstaben_und_Ziffern also beispielsweise: Petra (4654) 0001 34210921SHH oder Hubert (2342) 1281 Alle diese Verzeichnisse sind mit dieser Nummer (gesuchte_Zahl) fortlaufend nummeriert von 0001 bis 2500, aber eben in unterschiedlichen Ordnern. Also:
Jetzt möchte ich überprüfen, ob in den Verzeichnissen noch alle Unterverzeichnisse von 0001 - 2500 jeweils mit der fortlaufenden Nummer nach den Klammern vorhanden sind. Könnt ihr mir sagen wie das mit einem bash-skript schnell geht? Danke vorab! Kruppka
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11229
Wohnort: München
|
Also wenn ich das richtig verstehe, willst du über alle Unterverzeichnisse in einem Ordner laufen, dabei die Verzeichnisse, deren Name mit "<Name> (<Nummer>)" anfängt aufsammeln und die dann pro Name aus einer Liste streichen, die von 1 bis 2500 geht und dann die Nummern pro Name auflisten, die nicht gefunden wurden? Das wäre ein Ansatz in Python3:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 | #!/usr/bin/env python3
import os
import re
import sys
path = sys.argv[1]
path_regex = re.compile("^(\S+)\ \((\d{4})\).*")
names = {}
for root, dirs, files in os.walk(path):
for dirname in dirs:
r = path_regex.match(dirname)
print(dirname, type(r))
if r and len(r.groups()) == 2:
name, number = r.groups()
if name in names:
n = int(number)
if n in names[name]:
names[name].pop(names[name].index(n))
else:
print("unexpected directory %s" % (os.path.join(root, dirname)))
else:
names[name] = list(range(1,2501))
for name in names:
print("missing numbers for name %s:" % (name))
print(", ".join((str(i) for i in names[name])))
|
Aufruf dann mittels pyhton3 check_subdirs.py VERZEICHNIS_MIT_UNTERORDNERN kruppka schrieb: Alle diese Verzeichnisse sind mit dieser Nummer (gesuchte_Zahl) fortlaufend nummeriert von 0001 bis 2500, aber eben in unterschiedlichen Ordnern. [...] * Verzeichnis B:
Die Zahl wäre dann ja größer als das erwartete Maximum von 2500 - was soll in dem Fall passieren?
|
kruppka
(Themenstarter)
Anmeldungsdatum: 22. Januar 2006
Beiträge: 161
|
Danke erstmal! Du hast mich nur zum Teil verstanden: die Ziffer nach der "Klammerzahl" ist die fortlaufende Nummer also Peter (1122) 0001 Herbert (1122) 0002 Gottfried (1122) 0003 usw.
Ansonsten soll das Skript Ordnernamen ohne das genannte Schema ignorieren.
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11229
Wohnort: München
|
Ok, dann muss der reguläre Ausdruck noch so angepasst werden, dass er die vierstellige Nummer nach den Klammern als Gruppe nimmt - anders benannte Ordner werden schon ignoriert:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 | #!/usr/bin/env python3
import os
import re
import sys
path = sys.argv[1]
path_regex = re.compile("^(\S+)\ \(\d{4}\)\ (\d{4}).*")
names = {}
for root, dirs, files in os.walk(path):
for dirname in dirs:
r = path_regex.match(dirname)
if r and len(r.groups()) == 2:
name, number = r.groups()
if name not in names:
names[name] = list(range(1,2501))
n = int(number)
if n in names[name]:
names[name].pop(names[name].index(n))
else:
print("unexpected directory %s" % (os.path.join(root, dirname)))
for name in names:
print("missing numbers for name %s:" % (name))
print(", ".join((str(i) for i in names[name])))
|
Edit: Logikfehler korrigiert, damit auch beim ersten Auftauchen eines Namens die Nummer aus der Liste gestrichen wird.
|
kruppka
(Themenstarter)
Anmeldungsdatum: 22. Januar 2006
Beiträge: 161
|
Hmmm, das funktioniert nicht. Weil ich selbst nicht programmieren kann, weiß ich auch nicht weshalb...
Ich kann nur sagen, dass mir ziemlich viele Zahlen um die Ohren gehauen werden, wenn ich das Programm starte; dabei sagt mir mein Ordnungssinn (ich habe die 2500 Unterverzeichnisse nach und nach angelegt), dass maximal zehn Fehler in der Nummerierung stecken können. Wie wäre es, wenn entweder die Meldung kommt: Nummerierung 0001 - 2500 ok
oder etwa
Nummerierung bis 1250 fortlaufend, dann Fehler...
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11229
Wohnort: München
|
Gibt es denn nur eine fortlaufende Nummer pro Verzeichnis, insgesamt oder eine fortlaufende Nummer pro Name? Das Programm geht aktuell vom letzten Fall aus, also mit so einer Struktur:
$ tree -d test
test/
├── Foo (2012) 0001 5345345RE
├── Foo (2002) 0002 5352345RE
[...]
├── Foo (2102) 2448 DA347R5RE
└── Foo (2022) 2500 5352345RE
Würde es sich über eine Fehlende 2449 für den Namen Foo beschweren:
$ python3 check_dir.py test/
missing numbers for name Foo:
2449
|
kruppka
(Themenstarter)
Anmeldungsdatum: 22. Januar 2006
Beiträge: 161
|
Es gibt insgesamt eine fortlaufende Nummer über exakt neun Verzeichnisse. In Verzeichnis A sind beispielsweise 0001, 2449, 0461 in Verzeichnis B 0482 etc. bunt durcheinander gewürfelt. Es soll festgestellt werden, ob von 0001 bis 2500 die Reihe vollständig ist. Der Name ist ohnehin (fast) immer unterschiedlich, auch insgesamt: Verzeichnis A - Hans Müller (3512) 0001, Peter Hulk (8790) 2449 ...
Verzeichnis B - Petra Pansen (9023) 0482 ... Ich hoffe, das ist jetzt klar verständlich - Kommunikation is so ne Sache für mich 😀
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11229
Wohnort: München
|
Ah ok, es zählt also nur die vierstellige Nummer nach der Nummer in den Klammern - das vereinfacht die Sache natürlich:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 | #!/usr/bin/env python3
import os
import re
import sys
min_value = 1
max_value = 2500
path = sys.argv[1]
path_regex = re.compile("^\S+\ \(\d{4}\)\ (\d{4}).*")
numbers = list(range(min_value, max_value + 1))
for root, dirs, files in os.walk(path):
for dirname in dirs:
r = path_regex.match(dirname)
if r:
number = r.groups()[0]
n = int(number)
if n > max_value:
print("number %s is too high" % number)
elif n < min_value:
print("number %s is too low" % number)
elif n in numbers:
numbers.pop(numbers.index(n))
else:
print("number %s occurs more than once" % number)
if numbers:
print("missing numbers are:")
print(", ".join((str(n) for n in numbers)))
else:
print("complete sequence from {:04d} to {:04d}".format(min_value,
max_value))
|
|
track
Anmeldungsdatum: 26. Juni 2008
Beiträge: 7174
Wohnort: Wolfen (S-A)
|
Für Python- Gurus mag es reizvoll sein, sowas auf diese Weise zu programmieren, aber mir scheint ein Ansatz mit Shell- Mitteln übersichtlicher. Ich fasse vorab noch einmal die Vorgaben zusammen, zur Kontrolle, ob ich sie richtig verstanden habe:
Gesucht ist die vierstellige Nummer hinter der Klammer. Sie soll auf Vollständigkeit geprüft werden. Es sollen nur Verzeichnisnamen nach dem von Dir genannten Muster beachtet werden: [irgendwas] (0000) 0000[evtl. irgendwas] Es kommen keine Zeilenumbrüche innerhalb der Pfadnamen vor, und in den betrachteten Verzeichnisnamen auch keine Klammern außer denen um den 1. Zahlenblock Die Verzeichnisse dürfen beliebig tief geschachtelt sein; es könnte sogar vorkommen, dass ein nummeriertes Verzeichnis Unterverzeichnis eines anderen nummerierten Verzeichnisses ist. Gesucht ist entweder die Liste der fehlenden Zahlen in der Reihe, oder zumindest die 1. fehlende Zahl
Mit Shell-Mitteln würde man einen Verzeichnisbaum beliebiger Tiefe auf jeden Fall mit find abgrasen. (Schritt 1) Dadurch dass Zeilenumbrüche innerhalb der Pfadnamen ausgeschlossen sind, steht bei der Ausgabe dann jeder Pfad in einer eigenen Zeile: es reicht, einfach zeilenorientiert vorzugehen. Der bequemste Weg wäre, die Ergebnisse dann in einem Array abzulegen. Dabei nähme man geschickterweise gleich die Zählvariable als Index. (Schritt 2) Die passenden Teile kann man mit Hilfe von Parameter Expansions herausschälen. Um die Vollständigkeit zu testen kann man die Indizes von {0001..2500} durchlaufen lassen, und die fehlenden anzeigen. (Schritt 3)
In Code sähe das z.B. so aus: track@track:~$ find ./-test/ -type d # Grundversion von find:
./-test/
./-test/or'd"ner
./-test/or'd"ner/or'd"ner
./-test/ord ner
./-test/ord ner/Hubert (2342) 1281
./-test/ord ner/Hubert (2342) 1281/pfui
./-test/ord ner/Hubert (2342) 1281/Eva (1123) 0791
./-test/ord ner/Petra (4654) 0001 34210921SHH
./-test/--giftvogel
# Schritt 1: Version mit Regex-Filter, liefert nur alle passenden Verzeichnisnamen:
track@track:~$ find ./-test/ -type d -regextype posix-extended -regex '.+ \([0-9]{4}\) [0-9]{4}[^/]*'
./-test/ord ner/Hubert (2342) 1281
./-test/ord ner/Hubert (2342) 1281/Eva (1123) 0791
./-test/ord ner/Petra (4654) 0001 34210921SHH
track@track:~$ while read; do # Schritt 2: zeilenweise lesen und
name="${REPLY##*/}" # Namen ausschneiden
z="${name#*) }" # Zählvariable ausschneiden
z=${z:0:4} # auf 4 Stellen kürzen
echo "$z $name" # Test-Ausgabe
num[1$z]=$name # Array-Zelle befüllen
done < <( find ./-test/ -type d -regextype posix-extended -regex '.+ \([0-9]{4}\) [0-9]{4}[^/]*' )
1281 Hubert (2342) 1281
0791 Eva (1123) 0791
0001 Petra (4654) 0001 34210921SHH
track@track:~$ for i in {0001..0004} {0789..0793} {1279..1283}; do # Ich zähle hier mal nur in Auszügen ...
if [ "${num[1$i]}" = "" ]; then
echo "$i fehlt."
fi
done
0002 fehlt.
0003 fehlt.
0004 fehlt.
0789 fehlt.
0790 fehlt.
0792 fehlt.
0793 fehlt.
1279 fehlt.
1280 fehlt.
1282 fehlt.
1283 fehlt. Anmerkung: die 1 vor der Zählvariablen verhindert, dass der Index als oktal missverstanden wird. (→ Shell-Arithmetik !) Du siehst auf jeden Fall, dass der eigentliche Code bei diesem Shellskript gerade mal 11 Zeilen umfasst. So schlecht ist das gar nicht. LG, track
|
sinusQ
Anmeldungsdatum: 27. Oktober 2010
Beiträge: 193
Wohnort: Neudau
|
Ich hab das Skript von track noch um den Check, ob es doppelte Zahlen gibt, ergänzt: pi@raspi ~/scripting/05-ordnertest $ find test -type d
test
test/giftvogel
test/ordner
test/ord ner
test/ord ner/Hubert (2342) 1281
test/ord ner/Hubert (2342) 1281/pfui
test/ord ner/Hubert (2342) 1281/Eva (1123) 0791
test/ord ner/Josef (0123) 2222 asdf
test/ord ner/Michael (0123) 2222 asdf
test/ord ner/Petra (4654) 0001 34210921SHH
pi@raspi ~/scripting/05-ordnertest $
pi@raspi ~/scripting/05-ordnertest $
pi@raspi ~/scripting/05-ordnertest $
pi@raspi ~/scripting/05-ordnertest $ cat script
#!/bin/bash
while read; do
name="${REPLY##*/}"
z="${name#*) }"
z=${z:0:4}
echo $z >> tmp.txt
echo "$z $name"
num[1$z]=$name
done < <( find test/ -type d -regextype posix-extended -regex '.+ \([0-9]{4}\) [0-9]{4}[^/]*' )
for i in {0001..0004} {0789..0793} {1279..1283} {2220..2224}; do
if [ "${num[1$i]}" = "" ]; then
echo "$i fehlt."
fi
done
echo $(sort tmp.txt | uniq -d) " mehrfach!"
rm tmp.txt
pi@raspi ~/scripting/05-ordnertest $
pi@raspi ~/scripting/05-ordnertest $
pi@raspi ~/scripting/05-ordnertest $
pi@raspi ~/scripting/05-ordnertest $ ./script
2222 Josef (0123) 2222 asdf
1281 Hubert (2342) 1281
0791 Eva (1123) 0791
2222 Michael (0123) 2222 asdf
0001 Petra (4654) 0001 34210921SHH
0002 fehlt.
0003 fehlt.
0004 fehlt.
0789 fehlt.
0790 fehlt.
0792 fehlt.
0793 fehlt.
1279 fehlt.
1280 fehlt.
1282 fehlt.
1283 fehlt.
2220 fehlt.
2221 fehlt.
2223 fehlt.
2224 fehlt.
2222 mehrfach!
Sollten mehrere Verzeichnisse mehrfach vorkommen, würden diese aller in einer Zeile ausgegeben werden. Hier könnte man noch nacharbeiten, darauf hab ich aber keinen Fokus gelegt 😉 Möglicherweise geht's generell schöner, bessert mich ruhig aus ☺ Cheers,
M
|
kruppka
(Themenstarter)
Anmeldungsdatum: 22. Januar 2006
Beiträge: 161
|
Dumme Frage: wenn ich das Skript starte kommt folgende Fehlermeldung: | test: 10: test: Syntax error: redirection unexpected
|
Was hat das zu bedeuten?
|
track
Anmeldungsdatum: 26. Juni 2008
Beiträge: 7174
Wohnort: Wolfen (S-A)
|
Du müsstest mal Dein Skript - genau so, wie es bei Dir ist ! - in einem Codeblock zeigen. Sonst können wir nicht erraten, was in Deiner Zeile 10 steht. LG, track
|
kruppka
(Themenstarter)
Anmeldungsdatum: 22. Januar 2006
Beiträge: 161
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 | #!/bin/bash
while read; do
name="${REPLY##*/}"
z="${name#*) }"
z=${z:0:4}
echo $z >> tmp.txt
echo "$z $name"
num[1$z]=$name
done < <( find test/ -type d -regextype posix-extended -regex '.+ \([0-9]{4}\) [0-9]{4}[^/]*' )
for i in {0001..0004} {0789..0793} {1279..1283} {2220..2224}; do
if [ "${num[1$i]}" = "" ]; then
echo "$i fehlt."
fi
done
echo $(sort tmp.txt | uniq -d) " mehrfach!"
rm tmp.txt
|
So sieht es bei mir aus.
|
sinusQ
Anmeldungsdatum: 27. Oktober 2010
Beiträge: 193
Wohnort: Neudau
|
track schrieb: Du müsstest mal Dein Skript - genau so, wie es bei Dir ist ! - in einem Codeblock zeigen. Sonst können wir nicht erraten, was in Deiner Zeile 10 steht.
..genau. Und falls dein Verzeichnis nicht "test" heißt, das natürlich auch anpassen (vielleicht Ausgabe von tree zeigen). Hab gerade ein wenig herumgesucht - stimmt deine shebang-Zeile vielleicht nicht? Sollte #!/bin/bash sein..
|
track
Anmeldungsdatum: 26. Juni 2008
Beiträge: 7174
Wohnort: Wolfen (S-A)
|
... und Du rufst Dein Skript auch wirklich direkt mit
auf und nicht etwas mit sh -c oder so ? Wenn Du ausdrücklich einen falschen Interpreter aufrufst, kommt natürlich so eine Fehlermeldung, denn die sh / dash kennt keine Process Substitution. LG, track
|