Ich möchte mit find "unabhängig" vom aufgerufenen Verzeichnis immer
nur das am tiefsten liegende Verzeichnis finden.
Also in meiner BeispielVerzeichnissstruktur, möchte ich
--------------------------------------------------------
tmp/verzeichnis1/baum1/dir1/dir2
tmp/verzeichnis1/baum2/dir1
tmp/verzeichnis1/baum3/dir1/dir2/dir3
--------------------------------------------------------
finden.
Wie macht man soetwas mit find?
Vielen Dank im Voraus
Karl
Zu dem Zeitpunkt, wo find ein Directory findet, weiß es nicht, ob in dem
Directory noch weitere Directorys sind. Mit find alleine geht es daher
IMO nicht.
Du könntest find alle Directorys finden lassen und die einzelnen
Ergebnisse dann in einer Schleife jeweils um "/" ergänzt mit grep gegen
die ganze Ergebnisliste abtesten. Was nicht gefunden wird, ist ein Blatt
im Baum.
HTH
Bye
Achim
Ohne jetzt länger darüber nachgedacht zu haben, inwiefern diese
Konstruktion portabel ist und welche Sonderfälle sie u.U. nicht
berücksichtigt (mindestens auf Systemen, die Hardlinks auf
Verzeichnisse erlauben, funktioniert das nicht zuverlässig):
$ find <path> -type d -links 2
Erklärung: Jedes Verzeichnis hat mindestens zwei Links, nämlich den im
übergeordneten Verzeichnis und den "."-Eintrag im jeweiligen
Verzeichnis selbst. Für jedes Unterverzeichnis kommt dann noch je ein
Link hinzu, nämlich der ".."-Eintrag im jeweiligen Unterverzeichnis.
Allgemein hat also ein Verzeichnis mit n Unterverzeichnissen genau
(n+2) Links.
Du meintest am 23.07.10:
Ergänzend zu Achims Hinweisen: wie wäre es mit
ls -lR /tmp/verzeichnis1
zur Vorbereitung, und dann werden alle Dateien und Unterverzeichnisse
aussortiert?
Mögliche Suchbegriffe:
- Zeile vor "total"
- Zeile mit "/"
Und dann zählst Du "/"
Vielleicht geht auch
cd /tmp
ls -lR . | grep ^./verzeichnis1
als Vorbereitung.
Viele Gruesse
Helmut
"Ubuntu" - an African word, meaning "Slackware is too hard for me".
Mein Vorschlag: Skript "testfind1"
----<schnipp>----
#!/bin/bash
# Zu testendes Verzeichnis aus Aufrufparameter übernehmen, sonst
Default=aktuelles Verzeichnis:
TARGET_DIR="${1:-$PWD}"
for i in `find "$TARGET_DIR" -type d`; do
lowest=1
for j in `find "$i" -mindepth 1 -type d` ; do
lowest=0
break
done
if [ $lowest -eq 1 ] ; then
# ... hatte i kein weiteres Unterverzeichnis, das die Variable auf 0
gesetzt hätte:
echo "$i"
fi
done
----<schnapp>----
Keine Ahnung, ob das unter allen Eventualitäten funktioniert...
Ansgar
--
*** Musik! ***
> Also schrieb Karl Teuschler:
>
>> Hallo,
>>
>> Ich möchte mit find "unabhängig" vom aufgerufenen Verzeichnis immer
>> nur das am tiefsten liegende Verzeichnis finden.
>>
>> Also in meiner BeispielVerzeichnissstruktur, möchte ich
>> --------------------------------------------------------
>> tmp/verzeichnis1/baum1/dir1/dir2
>> tmp/verzeichnis1/baum2/dir1
>> tmp/verzeichnis1/baum3/dir1/dir2/dir3
>> --------------------------------------------------------
>> finden.
>>
>> Wie macht man soetwas mit find?
>
>
Nochmal nachgedacht und umgebaut: Skript "testfind2"
----<schnipp>----
#!/bin/bash
TARGET_DIR="${1:-$PWD}"
for i in `find "$TARGET_DIR" -type d`; do
if [ -z "`find "$i" -mindepth 1 -type d`" ] ; then
echo "$i"
fi
done
----<schnapp>----
:)
Danke
Karl
Funktioniert auch wunderbar!
danke
Karl
mkdir "${TARGET_DIR}/ker plauz"
Und tschüß!
-dnh
--
/ "[the block drivers and the buffer cache] aren't incestuous, \
\ they're just living in sin.. " -- Linus Torvalds /
Darum:
find ... | while IFS= read -r; do irgendwas "$REPLY"; done
oder,
while IFS= read -r; do irgendwas "$REPLY"; done < <(find ...)
oder (geht auch mit Dateien mit Zeilenumbruch im Namen) (GNU),
find ... -print0 | xargs -0 irgendwas
lg Mart
> oder (geht auch mit Dateien mit Zeilenumbruch im Namen) (GNU),
>
> find ... -print0 | xargs -0 irgendwas
oder allgemeiner, ebenfalls beschleunigt,
find ... -exec irgendwas {} +
(mit irgendwas z.B. "sh -c 'for i; do ...' find-sh")
Zumindest wenn "find" kein zu altes GNU-find (oder sonst ein
"kapottes") ist (mein eines GNU-find ist zu alt) ;)
> (mit irgendwas z.B. "sh -c 'for i; do ...' find-sh")
... und im 'do ..; done' immer schön "$i" quoten, sonst knallt man
auch da prompt wieder auf die Fresse! BTW: ich nehm bei sowas (hier
iterieren über Verz./Dateien) immer d bzw. f als Variablennamen ;)
-dnh, *huch*, nochmal die gleiche Zufallssig wie im letzten Post!
wird aber ersetzt, öhm, ich nehm mal einfach die neueste ;)
PS@Sven: da ich weiß, du "sammelst" solche Eigenarten, wenn du noch
Details von mir zu ~11 Jahre altem GNU Krams willst (inkl. Tests
und manpages) solltest du dich beeilen, da die Kiste ausgemustert
werden soll. Doku (man-/infopages) gingen auch später noch, aber
da steht halt nicht unbedingt immer alles drin ... Hm. Vielleicht
sollte ich einiges noch in ne VM umziehen, Plattenplatz hätte ich.
$ rpm -qa --last | tail -1
bc-1.04-74 Mon 16 Aug 1999 07:19:26
*g* (und CPU/MoBo sind vom Sommer 2000, der Rest teils deutlich
älter, teils "brandneu" :) Ein 2 Monate alter TFT an ner Mystique
von 1995 ... Hat sowas sonst noch wer als Hauptrechner? ;)
--
Sheridan: "I'll tell you one thing. If the primates that we came from had
known that some day politicians would come out of the gene pool, they'd have
stayed up in the trees and written evolution off as a bad idea!"
-- Babylon 5, 2x04 - A Distant Star
> Ansgar Strickerschmidt <dropspamhe...@arcor.de> wrote:
>> for i in `find "$TARGET_DIR" -type d`; do
>
> mkdir "${TARGET_DIR}/ker plauz"
mkdir "Wer Leerzeichen in Verzeichnisnamen verwendet frisst auch kleine
Kinder"
Das ist mir jetzt ein wenig zu kryptisch... -v, bitte, damit Lernende wie
ich auch mitkommen... so ein kleines kommentiertes Beispiel wäre nett.
-exec command {} +
This variant of the -exec action runs the specified
command on the selected files, but the command line is built by
appending each selected file
name at the end; the total number of invocations of the
command will be much less than the number of matched files. The command
line is built in
much the same way that xargs builds its command lines.
Only one instance of `{}' is allowed within the command. The command is
executed in the
starting directory.
-print0
True; print the full file name on the standard output,
followed by a null character (instead of the newline character that
-print uses). This
allows file names that contain newlines or other types
of white space to be correctly interpreted by programs that process the
find output. This
option corresponds to the -0 option of xargs.
wüsste nicht was ich da noch erklären sollte/könnte...
Kein Grund nicht darauf vorbereitet zu sein.
Mit dem (vermutlich ungewollten) Zeilenumbruch im "Verzeichnisnamen"
bekommt diese Aussage eine ganz neue Dimension.
Ich sehe da keinen.
Falls mehr als ein simples Kommando "irgendwas" benötigt wird,
also im allgemeinen Fall ein kleines Skript, dann ist der
genannte Shell-Aufruf eine Anregung, etwas passendes zu bauen.
Mit einer Shell-Schleife ist es bei wirklich vielen Argumenten
allerdings schon wieder relativ langsam.
Manchmal reicht eine Shell ohne Schleife aber schon aus.
Schönes Beispiel: Man möchte die gefundenen Argumente in ein
anderes Verzeichnis verschieben. Das + muß direkt auf {}
folgen, deshalb wäre folgendes ungültig,
find ... -exec mv {} /targetdir/ +
(Manche mv(1) bieten als Workaround an, das Directory mit
einer Option vor den Argumenten zu übergeben, aber darum
geht's hier nicht.)
Eine (dennoch sehr schnelle) Möglichkeit mit Shell ist
find ... -exec sh -c 'mv "$@" /targetdir/' find-sh {} +
Sprich:
Es mag natürlich jeweils speziellere Lösungen geben,
die schlanker, schneller, etc. sind. Aber zumindest kann
man mit "-exec +" und sh -c '...' (ggf. mit einer Schleife)
relativ einfach stets eine völlig robuste Lösung bauen.
OpenBSD, busybox und so manches ältere System kennen "-exec +"
noch nicht; dann gibt's vielleicht -print0|xargs -0.
Das ist insgesamt gesehen aber nicht besser verbreitet
und hat gelegentlich auch seine Tücken.
In der Praxis reicht ja in vielen Fällen ohnehin ein
"find ...|xargs" aus, aber die interessante Frage ist ja,
wie es bei Bedarf robust wird.
Randbemerkung: Häufig wird es bei "-exec +" bei einem einzigen
Aufruf bleiben, woran man sich gewöhnen kann. Man darf nie vergessen,
daß bei sehr vielen Argumenten mehrere Aufrufe daraus folgen können.
--
http://www.in-ulm.de/~mascheck/various/find/
> Zumindest wenn "find" kein zu altes GNU-find (oder sonst ein
> "kapottes") ist (mein eines GNU-find ist zu alt) ;)
Ja, bei GNU wurde es zwischen Jan'05 und Aug'06 eingeführt.
Letztendlich ist die Situation bzgl. der Verbreitung bei -print0
nicht anders, "-exec +" hat aber bessere Karten für die Zukunft,
da in POSIX. Mehr Details zur Verbreitung sammele ich in .sig.
> [ ~11 Jahre altem GNU Krams ]
Danke, aber mit etwas Zeit fand ich im Netz sogar noch
Source wie GNU find-3.2 ('91), -3.8 ('93), -4.0 ('94)
> Eine (dennoch sehr schnelle) Möglichkeit mit Shell ist
>
> find ... -exec sh -c 'mv "$@" /targetdir/' find-sh {} +
>
> Sprich:
> Es mag natürlich jeweils speziellere Lösungen geben,
> die schlanker, schneller, etc. sind. Aber zumindest kann
> man mit "-exec +" und sh -c '...' (ggf. mit einer Schleife)
> relativ einfach stets eine völlig robuste Lösung bauen.
Richtig. Man muss dabei aber natürlich auch noch die Eigenheiten der
von der Shell aufgerufenen Kommandos im Auge behalten. Hier z.B.
mögliche Nebeneffekte bei Dateinamen, die mit einem Minus beginnen...
> Ansgar Strickerschmidt wrote:
>> Also schrieb Sven Mascheck:
>>
>>> find ... -exec irgendwas {} +
>>>
>>> (mit irgendwas z.B. "sh -c 'for i; do ...' find-sh")
>>
>> -v, bitte
>
> ...(Ausführliches)...
> Randbemerkung: Häufig wird es bei "-exec +" bei einem einzigen
> Aufruf bleiben, woran man sich gewöhnen kann. Man darf nie vergessen,
> daß bei sehr vielen Argumenten mehrere Aufrufe daraus folgen können.
OK, da muss ich wohl mal damit spielen. Ich hab's jedenfalls mal
aufgehoben...
>>>> mkdir "Wer Leerzeichen in Verzeichnisnamen verwendet frisst auch
>>>> kleine
>>>> Kinder"
>
>>> Mit dem (vermutlich ungewollten) Zeilenumbruch im "Verzeichnisnamen"
>>> bekommt diese Aussage eine ganz neue Dimension.
>
>> Ich sehe da keinen.
>
> Na dann ließ dir den mkdir Befehl noch mal durch ;-)
?
Ich steh grad auf dem Schlauch...
Habe mein Letzteres mal durchgeführt (alle evtl. Umbrüche kommen vom
Newsreader...):
alpha@alpha04:~$ cd test1/
alpha@alpha04:~/test1$ mkdir "Wer Leerzeichen in Verzeichnisnamen
verwendet frisst auch kleine Kinder"
alpha@alpha04:~/test1$ ls -l
...
drwxr-xr-x 2 alpha alpha 4096 2010-07-27 10:11 Wer Leerzeichen in
Verzeichnisnamen verwendet frisst auch kleine Kinder
alpha@alpha04:~/test1$ cd Wer\ Leerzeichen\ in\ Verzeichnisnamen\
verwendet\ frisst\ auch\ kleine\ Kinder/
alpha@alpha04:~/test1/Wer Leerzeichen in Verzeichnisnamen verwendet frisst
auch kleine Kinder$ ls
alpha@alpha04:~/test1/Wer Leerzeichen in Verzeichnisnamen verwendet frisst
auch kleine Kinder$
Oder meintet ihr etwas vom Vorhergehenden?
>> [...] mit "-exec +" und sh -c '...' (ggf. mit einer Schleife) [...]
>
> Richtig. Man muss dabei aber natürlich auch noch die Eigenheiten der
> von der Shell aufgerufenen Kommandos im Auge behalten. Hier z.B.
> mögliche Nebeneffekte bei Dateinamen, die mit einem Minus beginnen...
..und um Beispielen zu geben, also dem Trenner "--" zwischen Optionen
und Argumenten, wenn unterstützt. Oder z.B. auch durch Voranstellen
von ./ (einer simplen, gern übersehenen Lösung),
sh -c 'for i; do echo "./$i"; done'
>> [...] mit "-exec +" und sh -c '...' (ggf. mit einer Schleife) [...]
>
> Richtig. Man muss dabei aber natürlich auch noch die Eigenheiten der
> von der Shell aufgerufenen Kommandos im Auge behalten. Hier z.B.
> mögliche Nebeneffekte bei Dateinamen, die mit einem Minus beginnen...
..und um Beispiele zu geben, also der Trenner "--" zwischen Optionen
und Argumenten, wenn unterstützt. Oder z.B. auch durch Voranstellen
von ./ (einer simplen, gern übersehenen Lösung),
sh -c 'for i; do echo "./$i"; done'
[supersede meines ersten posts mit hervorragendem Deutsch]
>> Mit dem (vermutlich ungewollten) Zeilenumbruch im "Verzeichnisnamen"
>> bekommt diese Aussage eine ganz neue Dimension.
>
> Ich sehe da keinen.
Die Rohansicht des Postings bringt Klarheit.
Im übrigen sind bei robuster Programmierung auch Zeilenumbrüche in
Dateinamen kein Problem.
Thomas