Pichuco
Anmeldungsdatum: 6. Juni 2009
Beiträge: 25
|
Hallo, ich versuche hier in einem (Bash-)Skript absolute Pfadnamen mit Umlauten zu verarbeiten, etwa: | [...]
for i in $(ls -al *.foo 2>/dev/null | awk '{print $5".*"$9}' 2>/dev/null); do grep "$i" $file; done > dups
cut -c70- dups | while read i; do
locale
ls -al "$i"
[...]
|
LC_ALL ist im gesamten Skript auf de_DE.iso88591 gesetzt und
exportiert. Diese Locale wird in locale -a auch gelistet. Mein Problem ist, dass die Zeilen der dups-Datei von dem ls nicht mehr
gefunden werden, weil: Der grep in der for-Schleife liefert die Namen mit Umlauten in der
Form bsp. "\374" steht für ein "ü". Die Treffer werden in der
dups-Datei als "<bla>374<faselrest>" dargestellt, also ohne das "\"
(wird wahrscheinlich von der Shell gefiltert). Hänge ich ein " | sed
-e '/\\374/ü'" noch nach dem grep dran, so findet der anschließende ls
in der while-Schleife die Datei auch. Gibt's da eine bessere Lösung? Danke und Grüße – Peter
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11176
Wohnort: München
|
Verrate doch lieber mal, was das eigentliche Ziel ist und auf was für einem Dateisystem die Daten liegen. Spricht etwas dagegen das Encoding der Dateinamen zu fixen, bevor man die Dateien weiterverarbeitet? Das ginge z.B. mit conmv ls ist generell eine schlechte Idee, wenn man über Dateien iterieren will - je nachdem was das genaue Ziel ist, würde ich da lieber find nutzen.
|
frostschutz
Anmeldungsdatum: 18. November 2010
Beiträge: 7651
|
ls | irgendwas ist praktisch immer falsch.
for file in *.foo
do
jetzt irgendwas mit "$file"
done
|
Pichuco
(Themenstarter)
Anmeldungsdatum: 6. Juni 2009
Beiträge: 25
|
Hallo, das mit dem "for i in *.foo" ändert nichts. Ich verwende "ls -al *.foo
2>/dev/null | awk '{print $5".*"$9}'" um daraus einen regulären
Ausdruck für den anschließenden grep zu bauen, der die Größe ($5 im
awk-Statement) mit einschließt. Der Hintergrund des Ganzen ist, dass ich Dateien des lokalen
Verzeichnisses in einem mit find erzeugten File (find /bla/sabbel
-type f) suchen möchte um anhand spezieller Merkmale identische
Dateien im globalen Verzeichnisbaum zu identifizieren
(md5sum-Prüfsummen dauern mir zu lange, dazu ist der Verzeichnisbaum
zu groß und ändert sich zu häufig). Peter
|
frostschutz
Anmeldungsdatum: 18. November 2010
Beiträge: 7651
|
Die Größe bekommst du im for mit stat -c %s "$file" .
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12801
|
fdupes arbeite nach meiner Erinnerung so, dass er die Größe zuerst evaluiert und erst dann den MD5 berechnet. Was auch immer man nimmt, das ist ein gelöstes Problem.
|
frostschutz
Anmeldungsdatum: 18. November 2010
Beiträge: 7651
|
rklm schrieb: fdupes arbeite nach meiner Erinnerung so, dass er die Größe zuerst evaluiert und erst dann den MD5 berechnet.
fdupes sollte auch dann keine md5 berechnen sondern Bytes vergleichen, dann kann es schon bei der ersten Abweichung aufhören. Ob das tatsächlich so geschieht weiß ich nicht. fdupes wird jedenfalls böse langsam wenn man tatsächlich viele gleich große, oder gar gleiche Dateien hat, und eine Option für Dateinamen o.ä. als Kriterium gibt es nicht.
Was auch immer man nimmt, das ist ein gelöstes Problem.
Man kann das alles ja ruhig selber machen, lernt man ja auch was dabei, nur sollte man dann trotzdem versuchen es irgendwie halbwegs richtig hinzubekommen, nur mit ls in eine Pipe ist das kein guter Anfang.
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12801
|
frostschutz schrieb: rklm schrieb: fdupes arbeite nach meiner Erinnerung so, dass er die Größe zuerst evaluiert und erst dann den MD5 berechnet.
fdupes sollte auch dann keine md5 berechnen sondern Bytes vergleichen, dann kann es schon bei der ersten Abweichung aufhören. Ob das tatsächlich so geschieht weiß ich nicht.
"Searches the given path for duplicate files. Such files are found by comparing file sizes and MD5 signatures, followed by a byte-by-byte comparison." Wenn man das effizient macht, dann sucht man alle Dateien, packt die mit der gleichen Größe in einen Korb und berechnet den MD5, während man eine Datei das erste Mal vergleicht. Man kann das auch so machen, dass man nur so lange liest, bis ein Vergleich scheitert. Oder man generiert den MD5 von nur einem Block (oder einer festen Anzahl Blöcke) auf der Platte. Da kann man sich noch viele Dinge ausdenken. ☺
fdupes wird jedenfalls böse langsam wenn man tatsächlich viele gleich große, oder gar gleiche Dateien hat, und eine Option für Dateinamen o.ä. als Kriterium gibt es nicht.
Möglicherweise liegt das daran, dass es halt nun mal aufwändig ist, Dateien auf Gleichheit zu vergleichen: wenn es viele gleiche gibt, dann muss jedes Programm die halt auch von vorne bis hinten lesen um sie zu vergleichen. ☺
Man kann das alles ja ruhig selber machen, lernt man ja auch was dabei, nur sollte man dann trotzdem versuchen es irgendwie halbwegs richtig hinzubekommen, nur mit ls in eine Pipe ist das kein guter Anfang.
👍 Das stimmt.
|
track
Anmeldungsdatum: 26. Juni 2008
Beiträge: 7174
Wohnort: Wolfen (S-A)
|
Grundsätzlich ist es keine gute Idee mit ls zu parsen . Ansonsten macht erfahrungsgemäß nur cut Ärger mit Umlauten und überhaupt mit Mehrbyte-Zeichen. Allerdings: wenn Du mit iso-8859 arbeitest UND auch tatsächlich keine utf8- Zeichen vorkommen, sollte das kein Problem sein. Die Geschichte mit sed weist allerdings darauf hin, dass eben doch irgendwo utf-8 verwendet wird. Du solltest
Dein Problem in überschaubaren Teileinheiten testen und vielleicht mal etwas mehr verraten was du konkret erreichen willst. Dann können wir auch konkret weiter helfen.
LG, track
|
Pichuco
(Themenstarter)
Anmeldungsdatum: 6. Juni 2009
Beiträge: 25
|
Hallo, einen Schritt weiter: Das Problem liegt in dem Archiv-File, wie es erzeugt wird: | find $basedir -iname '*.foo' -ls | grep -v $(pwd) >file
|
Das find-Kommando lasse ich hier mit der Option "-ls" laufen um im
gleichen Lauf auch die Filesize zu erhalten. Im Outputfile steht dann
"\374" mit insgesamt 4 Zeichen. Aus find(1): 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 | [...]
-ls True; list current file in ls -dils format on standard output.
The block counts are of 1K blocks, unless the environment vari-
able POSIXLY_CORRECT is set, in which case 512-byte blocks are
used. See the UNUSUAL FILENAMES section for information about
how unusual characters in filenames are handled.
[...]
-ls, -fls
Unusual characters are always escaped. White space, backslash,
and double quote characters are printed using C-style escaping
(for example `\f', `\"'). Other unusual characters are printed
using an octal escape. Other printable characters (for -ls and
-fls these are the characters between octal 041 and 0176) are
printed as-is.
[...]
|
Also Works as Designed... Die Frage ist nun wie bekomme ich die Octal-Schreibweise in eine
iso88591-kodierte Form? Peter
|
frostschutz
Anmeldungsdatum: 18. November 2010
Beiträge: 7651
|
evtl. normalerstring=$(echo -e "$escaperstring") Würde da dann aber eher find -printf '%s %p' oder sowas in der Art nehmen.
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12801
|
Pichuco schrieb:
einen Schritt weiter: Das Problem liegt in dem Archiv-File, wie es erzeugt wird: | find $basedir -iname '*.foo' -ls | grep -v $(pwd) >file
|
Also, der grep ist überflüssig: das kann man einfacher haben mit "-path": | find "$basedir" ! -path "$(pwd)" -iname '*.foo'
|
Noch besser ist es mit "-prune": | find "$basedir" -path "$(pwd)" -prune -o -iname '*.foo'
|
weil dann der ganze Teilbaum nicht durchsucht wird.
Das find-Kommando lasse ich hier mit der Option "-ls" laufen um im
gleichen Lauf auch die Filesize zu erhalten. Im Outputfile steht dann
"\374" mit insgesamt 4 Zeichen.
Du kannst das besser mit "-printf" machen: | find "$basedir" -path "$(pwd)" -prune -o -iname '*.foo' -printf '%s %p\n'
find "$basedir" -path "$(pwd)" -prune -o -iname '*.foo' -printf '%s %p\0'
|
Die Frage ist nun wie bekomme ich die Octal-Schreibweise in eine
iso88591-kodierte Form?
Die Frage ist erst mal, was willst Du am Ende erreichen? Wenn Du wirklich alle Dateinamen einzeln verarbeiten willst und sie ungewöhnliche Zeichen enthalten, dann würde ich "-print0" nutzen und nachher über alle Dateien iterieren oder gleich mit "-exec" ein Shell-Skript ausführen. In beiden Fällen ist es einfacher, die Größe der Dateien nachher mit stat zu ermitteln. 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 | # Variante 1
find "$basedir" -path "$(pwd)" -prune -o -iname '*.foo' -print0 >file
xargs --null -a file sh -c '
for f; do
size=$(stat -c %s "$f")
# ...
done
' --
# Variante 2
find "$basedir" -path "$(pwd)" -prune -o -iname '*.foo' -exec sh -c '
for f; do
size=$(stat -c %s "$f")
# ...
done
' -- {} +
|
Ciao robert
|