Ich muss eine Datei * .sh aus meinem Verzeichnis und meinen Unterverzeichnissen finden und sie ohne vollständigen Pfad anzeigen

355
Saken
find . -iname "*.sh" | sed 's/[.]sh$//' ./backup/samukano/ex04/who_am_i ./backup/samukano/ex05/people ./days/day01/samukano/ex01/print_groups ./days/day01/samukano/ex02/find_sh ./samukano/ex04/who_am_i ./samukano/ex05/people 

Und ich brauche nur

who_am_i people ... people 
0

2 Antworten auf die Frage

1
ivanivan
find . -iname "*.sh" -exec basename {} \; | sed s/\.sh//g 

Das basenameDienstprogramm entfernt alle Verzeichnisinformationen aus einem Pfad - relativ oder absolut.

Das dirnameDienstprogramm führt bei Bedarf das Gegenteil aus.

Ihr `sed` Befehl ist schlimmer als die OPs. Sehen Sie, was es mit `what.a.shame.sh` tut. Kamil Maciorowski vor 5 Jahren 0
0
Kamil Maciorowski

tl; dr

Tragbar, nicht robust:

find . -type f \( -name "*.sh" -o -name "*.Sh" -o -name "*.sH" -o -name "*.SH" \) | sed -e 's|^.*/||' -e 's/[.][sS][hH]$//' 

Robust, zum Analysieren als nullterminierte Zeichenfolgen:

find . -type f -iname "*.sh" -printf "%f\0" | sed -z 's/[.][sS][hH]$//' 

Intern robust mit möglicherweise mehrdeutiger Ausgabe zum Anzeigen:

find . -type f -iname "*.sh" -printf "%f\0" | sed -z 's/[.][sS][hH]$/\n/' 


Volle Antwort

Es gibt viele Möglichkeiten, einige robuster als andere. Außerdem verfügen die Tools, die Sie verwenden möchten, überlappende Funktionen. Viele davon sind jedoch nicht POSIX-fähig, sodass Sie möglicherweise nicht über die erforderlichen Optionen verfügen.

Außerdem kann jedes Verzeichnis des Dateinamens Zeilenumbrüche und andere merkwürdige Zeichen enthalten. Um Dateinamen auf eine robuste Weise zu analysieren, möchten Sie sie als nullterminierte Zeichenfolgen behandeln.

Dann möchten Sie das Ergebnis ohnehin mit Zeilenumbrüchen (dh regulären Strings) drucken, um die Lesbarkeit zu gewährleisten (allerdings besteht die Gefahr einer mehrdeutigen Ausgabe).

Werkzeuge unterstützen normalerweise nullterminierte Zeichenfolgen mit Nicht-POSIX-Erweiterungen.


Um beispielsweise diese vollständigen Pfade, die das Hauptproblem darstellen, loszuwerden, können Sie Folgendes verwenden:

  • find . -printf "%f", aber Ihr findkann oder kann nicht unterstützen -printf;
  • oder basename;
  • oder sogar sed.

Zum Abisolieren können .shSie verwenden:

  • basename path_to_process .sh, aber die Groß- und Kleinschreibung wird berücksichtigt, und ich denke, dass Sie -inameaus einem bestimmten Grund verwendet wurden (Hinweis -inameist für POSIX nicht erforderlich);
  • oder sed(wie Sie es getan haben), wobei die Groß- und Kleinschreibung nicht beachtet werden kann.

Diese Analyse ist nicht erschöpfend.


Die robusteste Version ohne Berücksichtigung von Groß- und Kleinschreibung gibt nullterminierte Zeichenfolgen zurück. Dies macht die Ausgabe für die weitere Analyse absolut zuverlässig:

find . -type f -iname "*.sh" -printf "%f\0" | sed -z 's/[.][sS][hH]$//' 

Dasselbe Ergebnis, das von Menschen lesbar und möglicherweise mehrdeutig ist:

find . -type f -iname "*.sh" -printf "%f\0" | sed -z 's/[.][sS][hH]$/\n/' 

Die Mehrdeutigkeit manifestiert sich so:

foo bar 

Gab es zwei Skripte: foo.shund bar.sh? oder nur einer foo(newline here)bar.sh?

Es wird noch verwirrender, wenn Sie nicht verwenden können sed -zund müssen Input liefern sedals Newline-terminierten Strings. In diesem Fall foo.sh(newline here)bar.shgeneriert eine einzelne Datei auch die obige Ausgabe.

Was passiert, wenn Ihr sedTräger -zaber findnicht unterstützt -printf? Vielleicht ist Ihr basenameTräger -z. Dies sollte völlig robust sein:

find . -type f -iname "*.sh" -exec basename -z -a {} + | sed -z 's/[.][sS][hH]$//' 

oder ohne die Unterstützung für -a:

find . -type f -iname "*.sh" -exec basename -z {} \; | sed -z 's/[.][sS][hH]$//' 

Ich kann sehen, dass Ihr findSupport unterstützt -iname, es kann jedoch nicht sein. Was wäre, wenn es nicht wäre? Ganz naiver aber funktionierender Ansatz:

find . -type f \( -name "*.sh" -o -name "*.Sh" -o -name "*.sH" -o -name "*.SH" \) ... 

Wie Sie sehen, hängt alles von den verfügbaren Optionen ab.


Angenommen, Ihre Pfade verwenden einen sicheren Satz druckbarer Zeichen (keine Zeilenumbrüche usw.). Dieser Befehl sollte tragbar und gut genug sein:

find . -type f \( -name "*.sh" -o -name "*.Sh" -o -name "*.sH" -o -name "*.SH" \) | sed -e 's|^.*/||' -e 's/[.][sS][hH]$//'