Existe-t-il un moyen de demander au shell cmd de Windows d’étendre les chemins génériques?

37

De temps en temps, l'incapacité du shell cmd à développer des chemins génériques peut vraiment être un inconvénient. J'ai dû passer 100 fichiers dans un répertoire à un programme et je ne pouvais pas taper * .ext. Au lieu de cela, j'ai utilisé le 'ls' de mingw pour vider la liste dans un fichier, puis j'ai remplacé les nouvelles lignes par des espaces, copiées et collées dans cmd. C'est un cauchemar.

Je suppose que la réponse sera non, mais est-ce que quelqu'un a réglé le problème ou a trouvé un moyen de le rendre plus facile?

cemuler
la source
2
Avez-vous envisagé d'utiliser quelque chose comme Powershell à la place?
I suspect the answer will be no, but has anyone dealt with this or come up with any way to make this easier? En fait, j'ai le problème opposé, j'essaie de trouver un moyen de faire en sorte que l'interpréteur de commandes traite sa liste comme des chaînes et l' empêche de les représenter comme des caractères génériques. Par exemple, for %i in (foobar baz really?) do @echo %itraitera le dernier élément ( really?) comme caractère générique de nom de fichier, et l' ignorer s'il n'y a pas de fichiers nommés really1, reallyzetc. ☹
Synetech
1
@ Synetech - ?n'est pas un caractère légal pour les noms de fichiers dans le système de fichiers Windows. Le caractère ne peut être interprété que comme un caractère générique. Voir Dénomination de fichiers, chemins d'accès et espaces de noms sur MSDN et Utilisation de caractères génériques dans TechNet.
jww le

Réponses:

18

DOS, et par conséquent Windows cmd.exe, n’a jamais supporté l’extension générique par le shell. C'était toujours à l'application de faire l'expansion.

Cela signifie que vous devrez toujours trouver un autre itinéraire si vous utilisez une application qui ne prend pas en charge l'expansion. Vous pourriez:

  • Utilisez une boucle FOR pour exécuter certaines commandes sur tous les fichiers qui vous intéressent
  • Utilisez dir /b > list.txtpour utiliser la dircommande afin de développer et de mettre la liste des fichiers dans un fichier texte (vous pouvez alors utiliser quelque chose comme une formule Excel si vous êtes vraiment désespéré de produire une liste de commandes à coller cmd, ou vous pouvez utiliser Excel pour transposer les cellules de sorte que tous les noms de fichiers soient sur la même ligne.)
Malvineux
la source
Il a expliqué que ce serait un cauchemar de sortir les résultats de dir dans un fichier et de traiter manuellement le filtrage et la copie. La réponse de wmz et bien sûr la mienne fonctionneraient sans filtrer manuellement le contenu des fichiers.
Wullxz
1
@wullxz: Peut-être, mais pour ceux qui ne sont pas familiers avec Powershell et désireux de le faire de manière ponctuelle, cela pourrait être considérablement plus rapide - et l'idée derrière ce site est de fournir des solutions utiles pour les personnes de tous niveaux de compétences auxquels se référer maintenant et à l'avenir. l’avenir, il n’ya donc vraiment pas lieu de s’offusquer de moi car vous pensez que ma réponse n’est pas aussi bonne que la votre
Malvineous
1
"DOS, et par conséquent le cmd.exe de Windows, n'a jamais supporté l'expansion du caractère générique par le shell." - Ce n'est pas vrai selon Microsoft. Voir Utilisation de caractères génériques sur TechNet. (Mais je pense que vous avez raison en pratique: o. Sinon, je ne serais pas là pour essayer de comprendre pourquoi les fichiers ne sont pas appariés)
2015
1
@jww: Le lien que vous avez posté explique l'utilisation standard des caractères génériques, mais je ne vois aucune mention de leur extension par le shell. Contrairement à UNIX (et aux versions ultérieures Linux et Mac), Microsoft a laissé l’extension de caractère générique à chaque application individuelle à mettre en œuvre, en passant les paramètres de ligne de commande à l’état actuel.
Malvineous
1
La commande DOS 'dir Filespec / b' fonctionne vraiment bien, car elle crée une liste de fichiers, un par ligne. Avec le commutateur '/ s' supplémentaire, les noms de fichier sont complets (absolus) et peuvent facilement être transmis via une boucle for à tout autre programme en ligne de commande prenant un nom de fichier. C'est tout ce que nous pouvons faire de mieux, car Windows ne dispose pas d'une fonctionnalité de globbing appropriée.
David A. Gray
9

Utilisez simplement Powershell, qui est préinstallé sur Windows 7. Powershell est capable d’exécuter des commandes cmd et comprend les caractères génériques à n’importe quel endroit du chemin.

Pour démarrer Powershell, tapez simplement "powershell" dans le champ de recherche du menu Démarrer et appuyez sur Entrée.


Si l'application attend une chaîne contenant tous les noms de fichiers, c'est le bon script:

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

Passez $delimiter = " "à $delimiter = ","si votre application attend une liste de noms de fichiers séparée par des virgules.

Explication du code:

  • [string]$files = $nothing - crée une variable vide de type string
  • ; - est un séparateur pour plusieurs commandes, pas un pipeline!
  • ls *.txt | % { $files += $_.fullname + $delimiter } - obtient une liste de tous les fichiers texte et crée une chaîne avec tous les noms de fichiers séparés par le délimiteur
  • application.exe $files - appelle l'application et lui transmet la liste de fichiers

Vous pouvez même rechercher un modèle de fichier de manière récursive en ajoutant -recurseà ls *.txtafin que le code complet ressemble à ceci:

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

Edit:
Pour éviter les irritations, lset dirsont des alias de Get-ChildItemet %est un alias ForEach-Object. Je garde mon code avec des alias utilisés car ils sont plus courts.

EDIT 2018/04/25:
En 2012, PowerShell était relativement nouveau pour moi. Bien sûr, il existe un moyen plus simple, bien que ce ne soit pas aussi facile que la capacité d'expansion globale de unix / linux:

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

Explication:

  • $ () va d'abord évaluer l'expression à l'intérieur et va se remplacer par le résultat de cette expression (un peu comme les backtick le font en bash)
  • ls *.txt obtient les objets FileInfo de tous les fichiers qui correspondent au glob *.txt
  • PowerShell étant orienté objet, nous devons générer le nom complet de chaque objet FileInfo. Nommer simplement un attribut / une propriété dans PowerShell le génère par défaut. % { $_.FileName }fait cela pour nous. %boucle sur tous les éléments retournés par lset renvoie chaque objet FileName.
Wullxz
la source
2
Bien que PS soit certainement capable de répondre à toutes les demandes, il est judicieux de le familiariser avec ces informations. Ce n’est pas aussi simple que vous le suggérez. Courir start notepad++ *.txt(avec l' intention d'ouvrir tous les fichiers texte - notepad ++ utilisé comme il le fait de gérer plusieurs noms) vous mènera nulle part
WMZ
1
Vous pouvez contourner ce problème avec dir *.txt | % { notepad++.exe $_ }. J'ai essayé cela avec un simple bloc-notes, parce que je n'ai pas de bloc-notes ++, et cela a fonctionné. La commande reçoit une liste de tous les fichiers txt du répertoire en cours, la transmet à la commande suivante qui parcourt la liste et exécute le bloc-notes ++ avec le nom de fichier comme paramètre.
Wullxz
oui, mais ce n'est pas équivalent. Pensez grep "a b c"à rechercher l' une des chaînes répertoriées, où "ab c" serait élargie
wmz
5
L'exécution d'une commande avec une liste d'éléments en tant que paramètre n'est pas équivalente à l'exécution d'une commande plusieurs fois avec chaque élément d'une liste en tant que paramètre. Un autre exemple: copy a+b+c resultet copy a result copy b result copy c result. (et grep comme utilitaire existe dans PS, ça s'appelle select-string)
wmz
1
il est dommage que l'OP ne se soucie pas de sonner pour expliquer ...
wmz
8

Cela vous donnera une liste et la mettra également dans la variable nommée expanded_list. Mettez-le dans un fichier de commandes et exécutez-le myBatchFile name myPattern. Placez le motif avec des guillemets s'il contient des espaces. Correspond aux fichiers, pas de répertoires. Exécuter sans paramètres correspond à tous.

@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%

Vous pouvez ensuite exécuter votre commande avec my_command_exec %expanded_list%

ATTENTION! La taille maximale de la variable cmd est de 8191 caractères (XP et plus), il est donc possible de la dépasser! Vous ne pouvez pas compter sur l'utilitaire pour vous fournir toujours une liste complète. D'autre part, la longueur maximale de la ligne de commande est également de 8191, vous ne pourrez donc pas l'exécuter de toute façon.

wmz
la source
Notez que si aucun argument n'est spécifié, alors expand_list sera défini sur tous les fichiers du répertoire en cours, ce qui peut être ou ne pas être ce qui est voulu. Vous devrez peut-être ajouter un contrôle sans argument (par exemple, si "% 1" == "" ...)
JasonM1
3

Cela fonctionne dans cmd.exe

dir /b *.ext

ou

echo | dir /b *.ext
utilisateur619818
la source
Cela ne fonctionne que pour le nom du fichier, pas pour une partie du chemin. Par exemple dir /b TortoiseSVN\bin\sv*.exemontrera svn.exeet svnadmin.exe. Mais dir /b TortoiseSVN\bi*\svn.exemontre une erreur de syntaxe.
Styfle
1
vérifier dir /s /b. Cela vous donne le chemin complet.
WesternGun
3

Notez que ceci est dans le commentaire aux affiches dans un fil séparé user619818 et styfle)

DIR peut et permet de rechercher dans tous les sous-répertoires les fichiers correspondant à un type spécifique.

Remarque: le répertoire racine dans lequel tous les sous-répertoires sont situés est supposé être "C: \ Mon programme \ Racine \", car l'auteur n'a pas indiqué de chemin d'accès sous lequel se trouvent ces répertoires.

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

cela donnera les chemins d'accès complets et les noms de fichiers des fichiers sources.

si vous ne voulez que les noms de fichiers, vous devrez procéder comme suit

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

En supposant que vous souhaitiez déplacer tous ces fichiers de "C: \ Mon programme \ Root \ Sub Directories \ *. ext" vers "D: \ Singlefolder \ *. ext", procédez comme suit:

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

Espérons que cela aide les autres à l'avenir. :)

Ben Personick
la source
1

C'est vieux, mais avec le sous-système Linux pour Windows, il est assez commun d'avoir bash dans votre PATH maintenant. Si tel est le cas, cela pourrait faire l'affaire pour vous:

bash -c 'cat *.txt'
Richard
la source
notez que les guillemets simples ne sont pas spéciaux dans Windows cmd . Par conséquent, si vous exécutez la commande ci-dessus à partir de cmd, cela ne fonctionnera pas. Et cela s'applique également aux systèmes avec Cygwin ou d'autres environnements bash
phuclv