Gibt es eine Möglichkeit, mit der Windows-Cmd-Shell Platzhalterpfade zu erweitern?

37

Gelegentlich kann die Unfähigkeit der cmd-Shell, Platzhalterpfade zu erweitern, wirklich zu Unannehmlichkeiten führen. Ich musste 100 Dateien in einem Verzeichnis an ein Programm übergeben und konnte * .ext nicht eingeben. Stattdessen habe ich mingws 'ls' verwendet, um die Liste in eine Datei zu kopieren, und dann die Zeilenumbrüche durch Leerzeichen ersetzt, kopiert und in cmd eingefügt. Ein wahrer Albtraum.

Ich vermute, die Antwort wird nein sein, aber hat sich jemand damit befasst oder eine Möglichkeit gefunden, dies zu vereinfachen?

cemulieren
quelle
2
Haben Sie darüber nachgedacht, stattdessen etwas wie Powershell zu verwenden?
I suspect the answer will be no, but has anyone dealt with this or come up with any way to make this easier? Tatsächlich habe ich das gegenteilige Problem. Ich versuche herauszufinden, wie der Befehlsinterpreter seine Liste als Zeichenfolgen behandeln und verhindern kann, dass sie als Platzhalter interpretiert werden. Zum Beispiel for %i in (foobar baz really?) do @echo %iwird das letzte Element (Behandlung really?) als Dateinamen Platzhalter, und es überspringt , wenn es keine Dateien mit dem Namen sind really1, reallyzusw. ☹
Synetech
1
@Synetech - ?ist kein legales Zeichen für Dateinamen im Windows-Dateisystem. Das Zeichen kann nur als Platzhalter interpretiert werden. Siehe Benennen von Dateien, Pfaden und Namespaces in MSDN und Verwenden von Platzhalterzeichen in TechNet.
Jww

Antworten:

18

DOS und folglich Windows cmd.exeunterstützten niemals die Platzhaltererweiterung durch die Shell. Es lag immer an der Anwendung, die Erweiterung durchzuführen.

Dies bedeutet, dass Sie immer eine andere Route suchen müssen, wenn Sie eine Anwendung verwenden, die keine Erweiterung unterstützt. Du könntest:

  • Verwenden Sie eine FOR-Schleife , um einige Befehle für alle Dateien auszuführen, an denen Sie interessiert sind
  • Verwenden Sie dir /b > list.txtdie verwenden dirBefehl , um die Expansion durchzuführen und setzt die Liste der Dateien in eine Textdatei (Sie dann so etwas wie eine Excel - Formel verwenden könnten , wenn Sie wirklich verzweifelt sind eine Liste von Befehlen zu erzeugen , in einfügen cmd, oder Sie können Excel verwenden um die Zellen so zu transponieren, dass sich alle Dateinamen in derselben Zeile befinden.)
Bösartig
quelle
Er erklärte, dass es ein Albtraum wäre, die Ergebnisse von dir in eine Datei auszugeben und manuell zu filtern und zu kopieren. Die Antwort von wmz und natürlich meine würde funktionieren, ohne den Inhalt einer Datei manuell zu filtern.
Wullxz
1
@wullxz: Vielleicht, aber für jemanden, der nicht mit Powershell vertraut ist und dies einmalig tun möchte, könnte es erheblich schneller gehen - und die Idee hinter dieser Website ist es, nützliche Lösungen für Menschen aller Kompetenzstufen bereitzustellen, auf die man sich jetzt und in Zukunft beziehen kann die Zukunft, also gibt es wirklich keinen Grund, mich abzusagen, weil du denkst, meine Antwort ist nicht so gut wie deine.
Malvineous
1
"DOS und folglich Windows 'cmd.exe haben die Platzhaltererweiterung durch die Shell nie unterstützt." - Laut Microsoft nicht wahr. Siehe Verwenden von Platzhalterzeichen in TechNet. (Aber ich denke, Sie haben Recht in der Praxis: o. Andernfalls wäre ich nicht hier, um herauszufinden, warum Dateien nicht abgeglichen werden)
JWW
1
@jww: Der Link, den Sie gepostet haben, erklärt die Standardverwendung der Platzhalterzeichen, aber ich sehe keine Erwähnung, dass sie von der Shell erweitert werden. Im Gegensatz zu UNIX (und neueren Linux- und Mac-Versionen) überließ Microsoft die Implementierung einer Platzhaltererweiterung jeder einzelnen Anwendung und übergab die Befehlszeilenparameter unverändert.
Malvineous
1
Der DOS-Befehl 'dir Filespec / b' funktioniert sehr gut, da er eine Liste von Dateien erstellt, eine pro Zeile. Mit dem zusätzlichen Schalter '/ s' sind die Dateinamen vollständig qualifiziert (absolut) und können problemlos über eine for-Schleife an jedes andere Befehlszeilenprogramm übergeben werden, das einen Dateinamen erhält. Es ist das Beste, was wir tun können, da Windows keine ordnungsgemäße Globbing-Funktion hat.
David A. Gray
9

Verwenden Sie einfach Powershell, das unter Windows 7 vorinstalliert ist. Powershell kann Cmd-Befehle ausführen und versteht Platzhalter an jeder Stelle in einem Pfad.

Um Powershell zu starten, geben Sie einfach "Powershell" in Ihr Startmenü ein und drücken Sie die Eingabetaste.


Falls die Anwendung eine Zeichenfolge mit allen Dateinamen erwartet, ist dies das richtige Skript:

$delimiter = " "
[string]$files = $nothing ; ls *.txt | % { $files += $_.fullname + $delimiter } ; application.exe $files

Wechseln Sie $delimiter = " "zu, $delimiter = ","wenn Ihre Anwendung eine durch Kommas getrennte Liste von Dateinamen erwartet.

Erklärung des Codes:

  • [string]$files = $nothing - Erstellt eine leere Variable vom Typ string
  • ; - ist ein Trennzeichen für mehrere Befehle, keine Pipeline!
  • ls *.txt | % { $files += $_.fullname + $delimiter } - Ruft eine Liste aller Textdateien ab und erstellt eine Zeichenfolge mit allen durch das Trennzeichen getrennten Dateinamen
  • application.exe $files - ruft die Anwendung auf und übergibt ihr die Dateiliste

Sie können sogar rekursiv nach einem Dateimuster suchen, indem Sie es hinzufügen -recurse, ls *.txtsodass der vollständige Code folgendermaßen aussieht:

$delimiter = " "
[string]$files = $nothing ; ls *.txt -recurse | % { $files += $_.fullname + $delimiter } ; application.exe $files

Bearbeiten:
Um Irritationen zu vermeiden lsund dirAliase von Get-ChildItemund %ist ein Alias ​​für ForEach-Object. Ich behalte meinen Code mit verwendeten Aliasen, weil er kürzer ist.

EDIT 25.04.2018:
2012 war ich noch ziemlich neu in PowerShell. Natürlich gibt es einen einfacheren Weg, obwohl er nicht so einfach ist wie die Fähigkeit von Unix / Linux zur Glob-Erweiterung:

app.exe $(ls *.txt | % {$_.FullName})

Erläuterung:

  • $ () wertet zuerst den inneren Ausdruck aus und ersetzt sich durch die Ausgabe dieses Ausdrucks (ähnlich wie Backticks in bash)
  • ls *.txt Ruft FileInfo-Objekte aller Dateien ab, die mit dem Glob übereinstimmen *.txt
  • Da PowerShell objektorientiert ist, müssen wir den vollständigen Namen jedes FileInfo-Objekts ausgeben. Durch einfaches Benennen eines Attributs / einer Eigenschaft in PowerShell wird diese standardmäßig ausgegeben. % { $_.FileName }tut das für uns. durchläuft %alle von den lsObjekten zurückgegebenen Elemente und gibt jeden Dateinamen aus.
wullxz
quelle
2
Obwohl PS durchaus in der Lage ist, die Anforderungen zu erfüllen, ist der Ratschlag, sich damit vertraut zu machen, vernünftig - es ist nicht so einfach, wie Sie vorschlagen. Laufen start notepad++ *.txt(mit Absicht , alle Text - Dateien zu öffnen - gebrauchte Notepad ++ , wie es funktioniert mehrere Namen handhaben ) führt zu nichts
wmz
1
Sie könnten das umgehen mit dir *.txt | % { notepad++.exe $_ }. Ich habe das mit einem einfachen Notizblock versucht, weil ich keinen Notizblock ++ habe, und es hat funktioniert. Der Befehl empfängt eine Liste aller txt-Dateien im aktuellen Verzeichnis, gibt die Liste an den nächsten Befehl weiter, der die Liste durchläuft und notepad ++ mit dem Dateinamen als Parameter ausführt.
Wullxz
Ja, aber das ist nicht gleichbedeutend. Denken Sie darüber grep "a b c"nach, eine der aufgelisteten Zeichenfolgen zu finden , bei denen "ab c" eine erweiterte Liste wäre
wmz
5
Das Ausführen eines Befehls mit einer Liste von Elementen als Parameter entspricht nicht dem mehrmaligen Ausführen eines Befehls mit jedem Element aus einer Liste als Parameter. Ein weiteres Beispiel: copy a+b+c resultund copy a result copy b result copy c result. (und grep wie Utility gibt es in PS, es heißt select-string)
WMZ
1
upvoted, übrigens ist es schade, dass OP es nicht interessiert, sich zu melden, um zu erklären ...
wmz
8

Dies gibt Ihnen eine Liste und legt sie auch in die Variable mit dem Namen expanded_list. Legen Sie es in die Batch-Datei und führen Sie mit myBatchFile name myPattern. Schließen Sie das Muster in Anführungszeichen ein, wenn es Leerzeichen enthält. Stimmt mit Dateien überein, keine Verzeichnisse. Ohne Parameter ausführen stimmt mit allen überein.

@echo off
set expanded_list=
for /f "tokens=*" %%F in ('dir /b /a:-d "%~1"') do call set expanded_list=%%expanded_list%% "%%F"

echo expanded_list is: 
echo %expanded_list%

Sie können dann Ihren Befehl mit ausführen my_command_exec %expanded_list%

WARNUNG! Die maximale Größe der cmd-Variablen beträgt 8191 Zeichen (ab XP), daher ist ein Überlauf möglich! Sie können sich nicht darauf verlassen, dass das Dienstprogramm immer eine vollständige Liste enthält. Andererseits beträgt die maximale cmd-Zeilenlänge auch 8191, sodass Sie sie ohnehin nicht ausführen können.

wmz
quelle
Wenn keine Argumente angegeben sind, wird expand_list auf alle Dateien im aktuellen Verzeichnis gesetzt, die möglicherweise nicht den Anforderungen entsprechen. Möglicherweise möchten Sie also hinzufügen, dass keine Argumente vorhanden sind (z. B. wenn "% 1" == "" ...).
JasonM1
3

Dies funktioniert in cmd.exe

dir /b *.ext

oder

echo | dir /b *.ext
user619818
quelle
Dies funktioniert nur für den Dateinamen, nicht für einen Teil des Pfads. Zum Beispiel dir /b TortoiseSVN\bin\sv*.exewird zeigen svn.exeund svnadmin.exe. Aber dir /b TortoiseSVN\bi*\svn.exezeigt ein Syntaxfehler.
Styfle
1
überprüfen dir /s /b. Dies gibt Ihnen den vollständigen Pfad.
WesternGun
3

Beachten Sie, dass dies in Kommentar zu den Postern in einem separaten Thread steht (user619818 und styfle)

Mit DIR können und können Sie in allen Unterverzeichnissen nach Dateien suchen, die einem bestimmten Typ entsprechen.

Hinweis: Als Stammverzeichnis zur Überprüfung, unter welchem ​​alle Unterverzeichnisse liegen, wird "C: \ My Program \ Root \" angenommen, da der Autor keinen Pfadnamen angegeben hat, unter dem sich diese Verzeichnisse befinden

DIR /B /S "C:\My Program\Root\*.ext"

Dadurch werden die vollständigen Dateipfade und Dateinamen der Quelldateien angegeben.

Wenn Sie nur Dateinamen möchten, müssen Sie wie folgt vorgehen

FOR /F "Tokens=*" %A IN ('DIR /B /S "C:\My Program\Root\*.ext"') DO @( Echo.%~nxA )

Angenommen, Sie möchten alle diese Dateien von "C: \ My Program \ Root \ Sub Directories \ *. ext" nach "D: \ Singlefolder \ *. ext" verschieben.

FOR /F "Tokens=*" %A IN ('DIR /B /S "C:\My Program\Root\*.ext"') DO @( MOVE "%~A" "D:\Singlefolder\%~nxA" /Y )

Hoffe das hilft anderen in Zukunft. :)

Ben Personick
quelle
1

Dies ist alt, aber mit dem Linux-Subsystem für Windows ist es ziemlich üblich, Bash in Ihrem PATH zu haben. Wenn dies der Fall ist, könnte dies den Trick für Sie tun:

bash -c 'cat *.txt'
Richard
quelle
Beachten Sie, dass einfache Anführungszeichen in Windows cmd keine besonderen Merkmale aufweisen . Wenn Sie den obigen Befehl in cmd ausführen, funktioniert dies nicht. Dies gilt auch für Systeme mit Cygwin oder anderen Bash-Umgebungen
phuclv