ChickenLipsRfun2eat
Anmeldungsdatum: 6. Dezember 2009
Beiträge: 12067
|
Hallo! Ich habe mir gerade einen simplen Zähler gebastelt und suche eine Möglichkeit in der aktuellen Zeile an Position 0 etwas einzufügen. Beispiel: | find . -type d -exec bash -c 'echo -e "\r" $(find "{}" -type f | wc -l) "\t"' \; -printf " %P"
|
Um den Anfang nicht zu überschreiben habe ich bei der printf-Ausgabe nun einfach 5 Leerzeichen eingetragen, was natürlich funktioniert, aber unschön ist. Gibt es die Möglichkeit echo -e in den "Einfügemodus" zu setzen? Habe im manual nichts gefunden. Ziel war das Anzeigen der Ordner mit der Anzahl der enthaltenen Dateien, beim Rumspielen kam ich auf dieses "Problem" und bin neugierig, ob das umsetzbar wäre.
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11179
Wohnort: München
|
Am sinnvollsten ist es alles in einem Rutsch zu schreiben, statt den Wagenrücklauf zu bemühen. Und wenn man Ziffern innerhalb einer bestimmten Zeichenanzahl ausrichten will, bietet sich printf statt echo an. Man könnte alles im -exec Statement unterbringen:
| find . -type d -exec bash -c 'printf "%5s\t%s\n" "$(find "$1" -maxdepth 1 -type f -printf "\n" | wc -l)" "${1//.\/}"' _ {} \;
|
da dabei aber ein Haufen Bash-Shells gespawned werden müssen ist das aber unnötig langsam - etwas besser wäre es die Schleife außerhalb zu haben:
| while IFS= read -r -d '' line
do
printf "%5s\t%s\n" "$(find "$line" -maxdepth 1 -type f -printf "\n" | wc -l)" "$line"
done < <(find . -type d -printf "%P\0")
|
Man könnte sich auch überlegen das mit einer Skriptsprache wie Python >= 3.6 machen - das ist bequemer (man muss keine Rücksicht auf Zeilenumbrüche und sonstige Späße in Dateinamen nehmen) und schneller, weil man nur einmal über den Verzeichnisinhalt laufen muss (ggf. muss man das Rekursionslimit hochsetzen, wenn man große Mengen an verschachtelten Verzeichnissen hat):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 | #!/usr/bin/env python3
import pathlib
def count_files_in_dir(directory):
num_files = 0
for e in directory.iterdir():
if e.is_file():
num_files += 1
elif e.is_dir():
try:
count_files_in_dir(e)
except OSError:
pass
print(f'{num_files:>5}\t{directory}')
if __name__ == '__main__':
count_files_in_dir(pathlib.Path('.'))
|
|
ChickenLipsRfun2eat
(Themenstarter)
Anmeldungsdatum: 6. Dezember 2009
Beiträge: 12067
|
Danke für die Ausführungen! Ich werde ein wenig mit den Lösungen rumspielen und mich vermutlich für den python-Weg entscheiden, da ich dann gleich etwas mehr dazubauen kann 😉 Gäbe es denn theoretisch die Möglichkeit direkt im echo-Befehl einzufügen, anstatt zu überschreiben?
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11179
Wohnort: München
|
ChickenLipsRfun2eat schrieb: Gäbe es denn theoretisch die Möglichkeit direkt im echo-Befehl einzufügen, anstatt zu überschreiben?
Du kannst Ausdrücke und Variablen für den echo-Befehl expandieren lassen - also z.B.
| while IFS= read -r -d '' line
do
echo -e "$(find "$line" -maxdepth 1 -type f -printf "\n" | wc -l | printf "%5d\n")\t${line}"
done < <(find . -type d -printf "%P\0")
|
Da echo auf stdout schreibt, hat es selbst keine Kontrolle über bereits von der Shell angezeigten Text - mit dem Wagenrücklauf \r sagst du der Shell (bzw. genauer gesagt dem Terminal-(Emulator) ja nur, dass der Cursor an den Anfang der Zeile bewegt werden soll.
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12822
|
seahawk1986 schrieb:
da dabei aber ein Haufen Bash-Shells gespawned werden müssen ist das aber unnötig langsam - etwas besser wäre es die Schleife außerhalb zu haben:
Es gibt wahrscheinlich noch eine andere Möglichkeit, denn printf wiederholt das Muster, solange genügend Argumente vorhanden sind: | $ printf '|%d|%s|\n' 11 22
|11|22|
$ printf '|%d|%s|\n' 11 22 33
|11|22|
|33||
$ printf '|%d|%s|\n' 11 22 33 44
|11|22|
|33|44|
|
Wenn ich das richtig sehe, sollen hier Dateien pro Verzeichnis gezählt werden. Das geht viel einfacher und schneller so: | find -type f -exec dirname {} + | sort | uniq -c
|
Wenn man das noch gegen Sonderzeichen in Verzeichnisnamen absichern will, dann so: | find -type f -exec dirname -z {} + | sort -z | uniq -cz | xargs -r0 printf '%s\n'
|
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11179
Wohnort: München
|
Interessante Idee, die auf jeden Fall deutlich flotter als mein Beispiel für die Shell ist - dein Ansatz ignoriert allerdings alle Verzeichnisse, die keine Dateien enthalten.
|
ChickenLipsRfun2eat
(Themenstarter)
Anmeldungsdatum: 6. Dezember 2009
Beiträge: 12067
|
seahawk1986 schrieb: Da echo auf stdout schreibt, hat es selbst keine Kontrolle über bereits von der Shell angezeigten Text - mit dem Wagenrücklauf \r sagst du der Shell (bzw. genauer gesagt dem Terminal-(Emulator) ja nur, dass der Cursor an den Anfang der Zeile bewegt werden soll.
Danke! Damit erklärt sich, wieso es nicht gehen kann. Deine Abfrage gibt allerdings immer "0" aus bei der Zahl. Da kann ich schön nachgucken, wieso das so ist. rklm schrieb: Es gibt wahrscheinlich noch eine andere Möglichkeit…Sonderzeichen in Verzeichnisnamen absichern will, dann so: | find -type f -exec dirname -z {} + | sort -z | uniq -cz | xargs -r0 printf '%s\n'
|
Danke! Gefühlt ist die Abfrage aber langsamer. Müsste ich mit time messen.
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11179
Wohnort: München
|
ChickenLipsRfun2eat schrieb: Danke! Gefühlt ist die Abfrage aber langsamer. Müsste ich mit time messen.
Da die Ergebnisse erst sortiert werden müssen, beginnt die Ausgabe erst, wenn der find-Befehl komplett durchgelaufen ist - wenn man die Ausgabe in eine Datei schreiben lässt, spielt das von der Zeit her keine große Rolle, die Ausgabe in einem Terminal-Emulator ist da vergleichsweise langsam.
|
ChickenLipsRfun2eat
(Themenstarter)
Anmeldungsdatum: 6. Dezember 2009
Beiträge: 12067
|
War wohl eher ein "Netzwerkhänger". Mittlerweile ist rklm's Zeile mit Abstand die schnellste Lösung (Sogar schneller als python3) ☺ Aber ich habe es nicht eilig, wobei ich die Idee mit uniq -c zu zählen nicht mal auf dem Schirm hatte. Ich markiere hier mal als gelöst, da ich zum einen nun weiß, wieso es keinen "Einfügemodus" in echo gibt, und zum anderen viele Ansätze habe, mit denen ich nun weiterbasteln kann. Danke euch beiden!!!
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11179
Wohnort: München
|
ChickenLipsRfun2eat schrieb: War wohl eher ein "Netzwerkhänger". Mittlerweile ist rklm's Zeile mit Abstand die schnellste Lösung (Sogar schneller als python3) ☺
Bei meinen Messungen war das Abhängig von der Python-Version bzw. Distribution (unter Arch Linux war Python 3.7 etwas langsamer, unter Ubuntu 18.04 Python 3.6 etwas schneller) und der Größe des untersuchten Verzeichnisbaums - je komplexer der strukturiert ist (das Home-Verzeichnis unter Ubuntu 18.04 hatte einen Haufen Clone von Git-Repositories), desto länger braucht sort , um die Ergebnisse zu ordnen.
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12822
|
seahawk1986 schrieb: Interessante Idee, die auf jeden Fall deutlich flotter als mein Beispiel für die Shell ist - dein Ansatz ignoriert allerdings alle Verzeichnisse, die keine Dateien enthalten.
Stimmt. Dann würde ich es - anders als die anderen Beispiele - so machen: | find -type d -exec sh -c 'for d; do printf "%10d %s\n" $(find "$d" -maxdepth 1 -type f -printf . | wc -c) "$d"; done' -- {} +
|
Vielleicht fällt mir noch was anderes ein...
|