Cordess
Anmeldungsdatum: 14. Mai 2006
Beiträge: 466
|
Mit dem Befehl
kann ich eine Liste von Verzeichnissen erstellen.
Diese Liste möchte ich nun als Eingabe für weitere komplexe Befehle (-exec reicht nicht) verwenden.
Das Problem ist nur, ich möchte das ohne den Umweg, die Liste in eine Datei zu schreiben, lösen, geht das irgendwie? Also
Würde z.b. die Liste in eine Datei schreiben und mit der Datei liste.txt könnte ich dann weiterarbeiten, aber genau das möchte ich nicht.
Es sollte ohne das schreiben funktionieren. Der Pipe Operator | reicht dafür leider auch nicht aus. Auch würde ich gerne wissen, wie man die ausgegebenen Suchergebnisse in Hochkomma setzt, so dass z.B. Verzeichnisse, die ein Leerzeichen enthalten später beim weiterverarbeiten nicht als zwei Verzeichnisse interpretiert werden.
|
noisefloor
Ehemaliger
Anmeldungsdatum: 6. Juni 2006
Beiträge: 29041
Wohnort: WW
|
Hallo, also mit Python wüsste ich, wie das geht - aber als reines Schell-Skript muss dann doch wer anders sein Wissen in den Ring werfen 😉 Gruß, noisefloor
|
Cordess
(Themenstarter)
Anmeldungsdatum: 14. Mai 2006
Beiträge: 466
|
Ich versuche es gerade dadurch, in dem ich die Ausgabe in ein Bash Array schreibe. Wenn es mir gelingt, dann sag ich Bescheid. Wer aber bessere Vorschläge hat, kann die natürlich auch nennen. Gibt's in Bash eigentlich auch Listen die dynamisch wachsen können?
Momentan muss ich nämlich meinen find Befehl zweimal durchlaufen lassen, da ich ja nicht weiß, wie groß das Array werden soll.
|
greenmoon
Anmeldungsdatum: 10. März 2010
Beiträge: 269
|
Cordess schrieb: Diese Liste möchte ich nun als Eingabe für weitere komplexe Befehle (-exec reicht nicht) verwenden.
Was heißt für dich denn komplexere Befehle? Du kannst quasi direkt shellskripte/funktionen mit find durchjagen, da ist der Komplexität eigentlich kaum Grenzen gesetzt (siehe z.B. http://stackoverflow.com/questions/4321456/find-exec-a-shell-function)
|
noisefloor
Ehemaliger
Anmeldungsdatum: 6. Juni 2006
Beiträge: 29041
Wohnort: WW
|
Hallo, @Cordess: es wäre vielleicht hilfreich, wenn du noch (be-) schreibst, was du nach erstellen der Verzeichnisliste eigentlich noch machen willst. Könnte den Lösungsweg ja beeinflussen... Gruß, noisefloor
|
Cordess
(Themenstarter)
Anmeldungsdatum: 14. Mai 2006
Beiträge: 466
|
@ greenmoon & noisefloor Okay, ich würde sagen, dann erkläre ich kurz, was ich eigentlich machen möchte, das bezieht dann auch den komplexere Befehl mit ein. Im Prinzip möchte ich in einem Verzeichnis und allen dessen Unterverzeichnissen zuerst prüfen, ob es in diesen Unterverzeichnissen eine md5 Prüfsummendatei gibt
und wenn es keine gibt, dann soll mein Skript eine für die im jeweiligen Unterverzeichnis vorhandenen Dateien eine md5 Prüfsummendatei mit md5sum erstellen. Als Lösungsweg schwebte mir daher vor, zuerst eine Liste aller Verzeichnisse und Unterverzeichnisse aufzubauen und wenn ich die dann habe,
dann soll die Liste durchgegangen werden und dabei mit cd in das entsprechende Verzeichnis gewechselt werden um dann dort eine Abfrage zu machen,
ob die Datei md5sum.md5 schon vorhanden ist und wenn nicht, dann soll sie mit "md5sum * > md5sum.md5" erstellt werden.
Falls sie vorhanden ist, dann sollte ein Hinweis* ausgegeben werden. * Wobei ich hier später, wegen der Komplexität vielleicht noch, je nach dem, ob ich bei meinem Script eine Option als Parameter übergeben habe, dann nicht nur prüfen möchte, ob die md5sum.md5 Datei vorhanden ist, sondern auch, dass die Dateien dann anhand dieser Prüfsummendatei mit md5sum geprüft werden und wenn eine Datei, die im Verzeichnis liegt, in der md5dum.md5 Datei fehlt, diese mit aufgenommen wird und bei Dateien,
bei denen die Prüfsummen verschieden sind, die alte Prüfsumme nach manueller Frage des Benutzers gegebenenfalls überschrieben und eine neue erstellt werden soll. Das ganze soll als bash Skript realisiert sein. PS: Falls ein Verzeichnis Leerzeichen erhält, dann sollte das berücksichtigt werden.
|
sebix
Moderator, Webteam
Anmeldungsdatum: 14. April 2009
Beiträge: 5334
|
| files=$(find . -name '*.m4a')
while read -r m4afile; do
echo "$m4afile";
# whatever you want to do here
done <<< "$files"
|
|
Cordess
(Themenstarter)
Anmeldungsdatum: 14. Mai 2006
Beiträge: 466
|
sebix schrieb: | files=$(find . -name '*.m4a')
while read -r m4afile; do
echo "$m4afile";
# whatever you want to do here
done <<< "$files"
|
Bist du dir da sicher? Wenn ich dein Skript richtig verstehe, dann sucht es nach Dateien mit der Dateiendung .m4a und macht dann etwas, wenn es fündig geworden ist.
Wenn in einem Unterverzeichnis aber keine *.m4a Datei ist, dann macht es dort rein gar nichts.
Also nicht das, was ich suche. Es sollen ja md5 Dateien erstellt werden, wenn keine in dem Unterverzeichnis vorhanden sind. Das ist die wesentliche Aufgabe des Scripts. @all Ich bin jetzt etwas weiter gekommen, damit kann ich alle gefundenen Verzeichnisse in einem Array ablegen (PS: es ist wichtig, dass für dieses Skript die bash aufgerufen wird):
| liste=(`find -type d -exec echo \"{}\" \;`)
|
Jetzt muss ich die Liste nur noch Eintrag für Eintrag in z.b. einer for Schleife durchgehen und das machen, was ich machen will.
|
sebix
Moderator, Webteam
Anmeldungsdatum: 14. April 2009
Beiträge: 5334
|
Cordess schrieb: Jetzt muss ich die Liste nur noch Eintrag für Eintrag in z.b. einer for Schleife durchgehen und das machen, was ich machen will.
Ja genau das Rezept dazu hab ich dir gerade gegeben. Fueg dein eigenes find-Kommando ein, und in die Schleife eben die Logik die du brauchst. Ich habe dir deine Problemstellung "Verzeichnisliste erstellen und dann mit den Einträgen weiterarbeiten ohne sie in eine Datei umzuleiten" aber beantwortet. Wenn du noch was brauchst, musst du schon sagen was. Ich kann nicht einfach so eine Loesung aus dem Aermel schuetteln, wenn ich gar nicht weiss, wo dein Problem liegt.
|
Cordess
(Themenstarter)
Anmeldungsdatum: 14. Mai 2006
Beiträge: 466
|
sebix schrieb: Cordess schrieb: Jetzt muss ich die Liste nur noch Eintrag für Eintrag in z.b. einer for Schleife durchgehen und das machen, was ich machen will.
Ja genau das Rezept dazu hab ich dir gerade gegeben. Fueg dein eigenes find-Kommando ein, und in die Schleife eben die Logik die du brauchst. Ich habe dir deine Problemstellung "Verzeichnisliste erstellen und dann mit den Einträgen weiterarbeiten ohne sie in eine Datei umzuleiten" aber beantwortet. Wenn du noch was brauchst, musst du schon sagen was. Ich kann nicht einfach so eine Loesung aus dem Aermel schuetteln, wenn ich gar nicht weiss, wo dein Problem liegt.
Bedaure, aber das mit dem Array habe ich mir selber erarbeitet und hatte ich vorher, bevor du deinen Beitrag überhaupt gepostet hast und dein Beitrag ist schlichtweg Schrott gewesen, da
selbst wenn ich dein Skript an meine Bedürfnisse anpassen würde, deine while Schleife gar nichts tut, wenn es keine md5 Datei findet.
Du prüfst nämlich schon mit der Bedingung der while Schleif, ob eine md5 Datei vorhanden ist, damit macht deine Schleife nichts, wenn die Bedingung nicht erfüllt werden kann, was vorkommt bei Verzeichnissen ohne md5 Datei. Es klingt also eher so, als würdest du gerade auf Schadensbegrenzung dein vorheriges Posting rechtfertigen, das war nämlich nichts. Momentan habe ich das hier:
| liste=(`find -type d -exec echo \"{}\" \;`)
for i in ${!liste[*]}
do
echo ${liste[$i]}
cd ${liste[$i]}
done
|
Wobei ich hier momentan das Problem habe, dass cd die Fehlermeldung "Datei oder Verzeichnis nicht gefunden" liefert. Aber das werde ich sicher auch noch irgendwie rauskriegen.
|
user_unknown
Anmeldungsdatum: 10. August 2005
Beiträge: 17552
Wohnort: Berlin
|
Was spricht dagegen es gleich von find machen zu lassen und stattdessen den fehleranfälligen Weg über ein Array zu gehen?
| find -depth -type d -execdir bash -c "test -e {}/md5sum.lst && echo da {} || echo fehlt {} " ";"
da ./zeichnung
fehlt ./tiere
fehlt ./personen
fehlt ./angst
fehlt ./abraum
fehlt ./.
|
Statt 'echo da/fehlt' machst Du, wenn das klappt:
| find -depth -type d -execdir bash -c "cd {}; test -e md5sum.lst && (echo -n {}; ls -l md5sum.lst) || md5sum * > md5sum.lst" ";"
|
Zackadackada - everything done.
|
Cordess
(Themenstarter)
Anmeldungsdatum: 14. Mai 2006
Beiträge: 466
|
user unknown schrieb: Was spricht dagegen es gleich von find machen zu lassen und stattdessen den fehleranfälligen Weg über ein Array zu gehen?
Eigentlich nichts. Wenn es auch ohne Array geht und sich direkt innerhalb find realisieren lässt, dann nehme ich natürlich auch diese Lösung.
Deine Lösung funktioniert schon sehr gut, danke dafür. Ein kleines Problem gibt's aber dennoch, Verzeichnisse die ein Leerzeichen enthalten liefern noch folgenden Fehler: 1
2
3
4
5
6
7
8
9
10
11
12 | find -depth -type d -execdir bash -c "test -e {}/md5sum.md5 && echo da {} || echo fehlt {} " ";"
fehlt ./hans
bash: Zeile 0: test: ./onkel: Zweistelliger (binärer) Operator erwartet.
fehlt ./onkel bert
fehlt ./wutz
fehlt ./bert
fehlt ./a
fehlt ./c
fehlt ./b
fehlt ./d
da ./blubber
fehlt ./.
|
Mein Testverzeichnis hat z.B. folgende Struktur. "onkel bert" ist ein Verzeichnis, bei dem deine Lösung noch zu einem Fehler führt.
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 | tree
.
├── a
│ ├── bert
│ │ └── test.txt
│ ├── hans
│ │ └── eso.txt
│ ├── oldk.txt
│ ├── onkel bert
│ └── wutz
│ └── gzgjg.txt
├── b
│ └── ghg.txt
├── blubber
│ ├── hankaka.txt
│ └── md5sum.md5
├── c
│ └── dfgasd.txt
├── create_md5sum.sh
├── d
│ └── eeeeee.txt
├── ls
├── neu.sh
└── test.sh
9 directories, 13 files
|
|
Cordess
(Themenstarter)
Anmeldungsdatum: 14. Mai 2006
Beiträge: 466
|
Wenn ich die Verzeichnisse in Hochkomma setzte, geht es.
| find -depth -type d -execdir bash -c "test -e \"{}\"/md5sum.md5 && echo da {} || echo fehlt {} " ";"
|
Danke, der Rest sollte dann kein Problem mehr machen.
|
Cordess
(Themenstarter)
Anmeldungsdatum: 14. Mai 2006
Beiträge: 466
|
Ich habe jetzt noch den Sternoperator
durch eine eingebettete find Anweisung ersetzt, so dass die Verzeichnisse im aktuellen Verzeichnis keine Fehlermeldung mehr generieren.
| md5sum `find -maxdepth 1 -type f` > md5sum.md5
|
Damit würde der Einzeiler momentan so lauten:
| find -depth -type d -execdir bash -c "cd \"{}\"; test -e md5sum.md5 && (echo -n {}\/; ls md5sum.md5) || (md5sum `find -maxdepth 1 -type f` > md5sum.md5)" ";"
|
Aber wenn eine md5 Datei nicht vorhanden ist, dann führt das nun zu unerwünschten Nebeneffekten. D.h. das Script erstellt dann zwar die fehlenden md5 Prüfsummendateien,
aber es gibt auch Fehlermeldungen aus, wie das die ein oder andere Datei nicht gefunden wurde. PS: Um noch einmal zurück zu der obigen Arraylösung zu kommen-
Falls jemand weiß, warum bei der obigen Arraylösung der Befehl cd die oben genannte Fehlermeldung liefert, dann würde mich das auch noch interessieren.
Dieser find Einzeiler hat leider nämlich den Nachteil, dass er mit steigender Länge unübersichtlich wird und daher auch schlecht zu warten ist.
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12822
|
Cordess schrieb:
Falls jemand weiß, warum bei der obigen Arraylösung der Befehl cd die oben genannte Fehlermeldung liefert, dann würde mich das auch noch interessieren.
Du führst mit -exedir aus. Dann passt der Pfad des Verzeichnisses im Skript bei dem cd nicht mehr.
Dieser find Einzeiler hat leider nämlich den Nachteil, dass er mit steigender Länge unübersichtlich wird und daher auch schlecht zu warten ist.
Genau. Es gibt noch einen Weg, das über ein Shell-Skript zu machen, das von find aufgerufen wird: | find dir -type d -exec sh -c '
for d; do
( cd "$d" && test ! -f md5sum && md5sum * >md5sum 2>/dev/null )
done
' -- {} +
|
Vorteil ist: es wird nur eine Shell für mehrere Argumente ausgeführt, man braucht keine Shell-Arrays (das geht sogar mit der sh , weil man das Array der Shell-Argumente nutzt) und man muss nicht mit dem Quoting der Dateinamen herumhantieren. Was man aber eigentlich möchte, ist ein Vergleich der Modifikationszeiten der Dateien mit der Datei "md5sum". Dann würde man die Summen neu berechnen, wenn die Summendatei fehlt oder irgendeine der Dateien im Verzeichnis neuer ist als die Summendatei. Noch effizienter wird es, wenn man für jede einzelne Datei schaut, ob sie neuer ist als die Summendatei und nur dann neu berechnet. Dann muss man aber alte Summen aus der Datei (die also noch aktuell sind) mit neuen kombinieren. Das ist ein bisschen eklig. Die nicht komplett effiziente Lösung (also dir vorletzte) könnte man so machen: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 | find dir -type d -exec sh -c '
for d; do
(
if cd "$d" ; then
time=0
test -f md5sum && time=$(stat -c %Y md5sum)
for t in $(stat -c %Y *); do
if [ $t -gt $time ]; then
md5sum * >md5sum 2>/dev/null
break
fi
done
fi
)
done
' -- {} +
|
Ich übergebe einfach alles an md5sum und lasse die Fehler für Verzeichnisse nach /dev/null schreiben. find -depth muss man hier weglassen, weil sonst die geschriebenen md5sum-Dateien das aktuelle Verzeichnis ändern und das dann auf der nächsten höheren Ebene dazu führt, dass die md5sum-Datei auf jeden Fall neu geschrieben wird.
|