2017-04-07 1 views
0

Ich habe ein Skript, das find verwendet, um nach Dateien zu suchen, die Benutzereingaben entsprechen. Im Grunde gibt der Benutzer so etwas wie test* ein und es soll alle passenden Dateien finden.Wie wird ein Dateiname mit eingebetteten Wildcards übergeben, um ohne Beschränkung auf lokal gefundene Dateien zu finden?

Das Problem, das ich habe, ist, dass, wenn es eine Datei im aktuellen Verzeichnis gibt, das dem vom Benutzer eingegebenen Dateinamenmuster entspricht, wird nur nach dieser Datei gesucht. Das heißt, wenn der Benutzer fred* eingibt und sich im aktuellen Verzeichnis eine Datei namens frederica befindet, findet das Skript nur Dateien namens frederica. Hier ist ein Beispiel für das Problem:

>ls 
test1 test2 test3 test4 test5 words 
>tmp() 
> { 
> my_file="$1" 
> find . -iname "$my_file" 
> } 
>tmp test* 
./test1 
> 

Wenn ich tmp test* eingeben, würde ich erwarten, dass es die fünf Dateien test1 durch test5 zurückzukehren. Stattdessen gibt es nur die erste zurück. Wenn ich beispielsweise nach / suchte, würde es immer nur Dateien mit dem Namen test1 aus jedem Verzeichnis zurückgeben.

Das eigentliche Skript ist natürlich komplexer, und ich habe eine Workaround mit einer "Wildcard-Option" entwickelt (z. B. -w 1 bedeutet, führende und nachfolgende Sterne, etc.), aber ich möchte wirklich nur in der Lage sein um den Benutzer einen Dateinamen mit einem Platzhalter eingeben zu lassen.

Vielen Dank im Voraus

+0

Warum versuchen Sie nicht '' $ my_file'' oder auch nur '$ my_file' –

+0

Das scheint nicht zu helfen - setzen Sie einfache Anführungszeichen um' $ my_file' im Befehl find führt dazu, nichts während zu finden keine Anführungszeichen ergeben die gleichen Ergebnisse wie Anführungszeichen. –

+0

Dies ist sehr eng verwandt mit [Stop Shell Wildcard-Zeichenerweiterung?] (Http://stackoverflow.com/questions/11456403/stop-shell-wildcard-character-expansion). –

Antwort

2

Wenn Sie Ihre Funktion so, wie Sie tun nennen, die Shell, die den Aufruf interpretiert versucht, Dateien zu finden passende (diese Funktion vor dem Betreten der Fall ist), und verschiedene Dinge passieren kann:

  • Wenn Der Glob schlägt fehl und die failglob Shell-Option ist gesetzt, dann wird die Funktion überhaupt nicht ausgeführt. Sie haben dies wahrscheinlich wegen der Standard-Shell-Optionen nicht gesehen.

  • Andernfalls, wenn der Glob fehlschlägt und die Shell-Option nullglob gesetzt ist, dann ist das Ergebnis des Globs überhaupt nichts und es wird kein Argument an Ihre Funktion übergeben. Das haben Sie wahrscheinlich auch nicht erlebt.

  • Andernfalls, wenn der Glob fehlschlägt und die Shell-Option failglob nicht gesetzt ist, dann ist das Ergebnis des Globs, was auch immer der Glob-Ausdruck war, und dies wird als Argumentwert verwendet. Dann wird dieser Glob-Ausdruck unverändert an find übergeben und find macht was Sie wollen, da es Globbing intern implementiert. Du hast Glück, dass es funktioniert, aber es funktioniert.

  • Der Glob ist erfolgreich und führt zu einer Liste von Dateien, die als eine Liste von Argumenten für Ihre Funktion verwendet wird. Ihr Aufruf find mit $1, so dass nur das erste dieser Argumente berücksichtigt wird, was zu dem Ergebnis führt, das Sie nicht möchten.

Doppelte Quotierung oder einzelne Quotierung deaktiviert Globbing.Wenn aus einem Skript verwenden, können Sie also tun:

tmp "test*" 

Wenn Sie diesen Befehl aus der Befehlszeile verwenden, ist Ihre einzige Möglichkeit wäre, ganz zu deaktivieren Globbing auf, mit set -f, die sehr gut Nachteile haben könnten.

+0

Ihre Beschreibung entspricht meiner Erfahrung. Ich denke Failglob ist nicht so eingestellt, wenn es lokal keine passenden Dateien gibt, wird der Parm wie er ist (mit den Platzhaltern) weitergegeben und er funktioniert wie er sollte. –

+0

Leider ist das Deaktivieren von Globbing keine Option, daher klingt es so, als ob ich mit dem stecken geblieben wäre, was ich habe - mit der Option, das Skript die Platzhalter intern setzen zu lassen. Vielen Dank! –

+2

@RogerSinasohn In allen Fällen funktioniert es wie es soll, denn "wie es soll" hängt von den Shell-Spezifikationen ab, nicht davon, was Sie wollen oder erwarten ... – Fred

1

test* zu test1 test2 test3 test4 test5 erweitert. Sie betrachten nur $1, nämlich test1.

Versuchen Sie, es als tmp 'test*' zu nennen.

+0

Das funktioniert, aber es bedeutet, die Benutzer darin zu schulen, Parameter in einfache Anführungszeichen zu setzen, von denen ich glaube, dass sie nicht funktionieren. Aber ich denke, Sie sind vielleicht auf etwas - ist die Erweiterung von "Test *" innerhalb des Skripts passiert (wenn es _my_file_ zugeordnet ist) oder in dem eigentlichen Befehl, bevor das Skript startet? Das heißt, ist das Problem, dass die Eingabe von 'tmp test *' ist eigentlich das gleiche wie die Eingabe von 'tmp test1 test1 test3 test4 test5' so das Skript sieht nie sogar den Platzhalter? Es ist ein Shell-Problem? –

+0

Ja, wenn Sie ein Literal '*' übergeben möchten, müssen Sie es aus der Shell zitieren. –

+1

@RogerSinasohn, um Ihre Frage direkt zu beantworten: Der Glob wird erweitert * bevor * das Skript startet. Das Skript erhält einen Argumentvektor mit einer Liste einzelner Strings, einen pro Datei, und kann nicht wissen, was die ursprüngliche Befehlszeile war. –

Verwandte Themen