Есть ли способ получить оболочку Windows cmd для расширения пути подстановки?

37

Иногда неспособность оболочки cmd расширять пути подстановки может быть неудобством. Мне пришлось передать 100 файлов из каталога в программу, и я не смог набрать * .ext. Вместо этого я использовал msw 'ls', чтобы вывести список в файл, а затем заменил символы новой строки пробелами, скопировал и вставил в cmd. Совсем кошмар.

Я подозреваю, что ответ будет отрицательным, но кто-нибудь имел дело с этим или придумал какой-нибудь способ облегчить это?

cemulate
источник
2
Рассматривали ли вы вместо этого что-то вроде Powershell?
I suspect the answer will be no, but has anyone dealt with this or come up with any way to make this easier? На самом деле, у меня возникла противоположная проблема, я пытаюсь найти способ заставить интерпретатор команд обрабатывать свой список как строки и не допускать его интерпретацию как подстановочных знаков. Например, for %i in (foobar baz really?) do @echo %iбудет рассматривать последний элемент ( really?) в качестве имени файла шаблона, и пропустить его , если нет файлов с именем really1, reallyzи т.д. ☹
Synetech
1
@Synetech - ?недопустимый символ для имен файлов в файловой системе Windows. Символ может быть интерпретирован только как подстановочный знак. См. Имена файлов, путей и пространств имен в MSDN и Использование подстановочных знаков в TechNet.
15:15

Ответы:

18

DOS и, следовательно, Windows ' cmd.exeникогда не поддерживали расширение подстановочными символами в оболочке. Это всегда было за приложением, чтобы сделать расширение.

Это означает, что вам всегда придется искать другой маршрут, если вы используете приложение, которое не поддерживает расширение. Ты мог бы:

  • Используйте цикл FOR для запуска некоторых команд со всеми интересующими вас файлами
  • Используйте, dir /b > list.txtчтобы использовать dirкоманду, чтобы выполнить расширение и поместить список файлов в текстовый файл (тогда вы могли бы использовать что-то вроде формулы Excel, если вы действительно хотите создать список команд для вставки cmd, или вы можете использовать Excel транспонировать ячейки так, чтобы все имена файлов были в одной строке.)
Malvineous
источник
Он объяснил, что вывод результатов dir в файл будет кошмаром, а процесс фильтрации и копирования выполняется вручную. Ответ wmz и, конечно, мой, будут работать без ручной фильтрации содержимого файлов.
wullxz
1
@wullxz: Возможно, но для тех, кто не знаком с Powershell и хочет сделать это как разовое, это может быть значительно быстрее - и идея этого сайта состоит в том, чтобы предоставить полезные решения для людей всех уровней квалификации, к которым можно обратиться сейчас и в будущее, так что на самом деле нет нужды отговаривать меня, потому что вы думаете, что мой ответ не так хорош, как ваш.
Malvineous
1
«DOS и, следовательно, Windows cmd.exe, никогда не поддерживали расширение подстановочными символами в оболочке». - Не соответствует действительности в соответствии с Microsoft. См. Использование подстановочных знаков в TechNet. (Но я думаю, что вы правы на практике: o. В противном случае я бы здесь не пытался выяснить, почему файлы не совпадают)
jww
1
@jww: ссылка, которую вы разместили, объясняет стандартное использование подстановочных знаков, но я не вижу никаких упоминаний о том, что они были расширены оболочкой. В отличие от UNIX (и позже Linux и Mac), Microsoft оставила расширение подстановочного знака для каждого отдельного приложения для реализации, передавая параметры командной строки как есть.
Malvineous
1
Команда DOS 'dir Filespec / b' работает очень хорошо, потому что она создает список файлов, по одному на строку. С дополнительным ключом '/ s' имена файлов полностью определены (абсолютные) и могут быть легко переданы через цикл for любой другой программе командной строки, которая принимает имя файла. Это лучшее, что мы можем сделать, поскольку Windows не имеет надлежащей функции глобализации.
Дэвид А. Грей,
9

Просто используйте Powershell, который предустановлен в Windows 7. Powershell способен запускать команды cmd и понимает подстановочные знаки в любом месте пути.

Чтобы запустить Powershell, просто введите «powershell» в поле поиска в меню «Пуск» и нажмите Enter.


Если приложение ожидает строку со всеми именами файлов, это правильный сценарий:

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

Измените $delimiter = " "на, $delimiter = ","если ваше приложение ожидает разделенный запятыми список имен файлов.

Объяснение кода:

  • [string]$files = $nothing - создает пустую переменную типа string
  • ; - это разделитель для нескольких команд, а не конвейер!
  • ls *.txt | % { $files += $_.fullname + $delimiter } - получает список всех текстовых файлов и создает строку со всеми именами файлов, разделенными разделителем
  • application.exe $files - вызывает приложение и передает ему список файлов

Вы даже можете рекурсивно искать шаблон файла, добавив -recurseего ls *.txtтак, чтобы весь код выглядел так:

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

Изменить:
чтобы избежать раздражения, lsи dirпсевдонимы Get-ChildItemи %псевдоним ForEach-Object. Я держу свой код с использованием псевдонимов, потому что он короче.

РЕДАКТИРОВАТЬ 2018/04/25:
в 2012 году я был довольно новым для PowerShell. Конечно, есть более простой способ, хотя он не так прост, как способность unix / linux к расширению glob:

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

Объяснение:

  • $ () сначала вычислит выражение внутри и заменит себя выводом этого выражения (так же, как обратные пометки в bash)
  • ls *.txt получает объекты FileInfo всех файлов, которые соответствуют глобу *.txt
  • поскольку PowerShell является объектно-ориентированным, мы должны вывести полное имя каждого объекта FileInfo. Простое присвоение имени атрибуту / свойству в PowerShell выводит его по умолчанию. % { $_.FileName }делает это для нас. %перебирает все возвращаемые элементы lsи выводит каждый объект FileName.
wullxz
источник
2
Несмотря на то, что PS, безусловно, способен выполнить запрос, и совет для ознакомления с ним является здравым - это не так просто, как вы предлагаете. Запуск start notepad++ *.txt(с целью открыть все TextFiles - используется Notepad ++ , как это делает обрабатывать несколько имен) не добьешься
WMZ
1
Вы можете обойти это с dir *.txt | % { notepad++.exe $_ }. Я попробовал это с простым блокнотом, потому что у меня нет notepad ++, и это сработало. Команда получает список всех txt-файлов в текущем каталоге, передает список следующей команде, которая проходит по списку и выполняет notepad ++ с именем файла в качестве параметра.
wullxz
да, но это не эквивалентно Подумайте о том, grep "a b c"чтобы найти любую из перечисленных строк, где «ab c» будет расширен список
wmz
5
Выполнение команды со списком элементов в качестве параметра не эквивалентно многократному выполнению команды с каждым элементом из списка в качестве параметра. Другой пример: copy a+b+c resultа copy a result copy b result copy c result. (и в PS существует утилита типа grep, она называется select-string)
wmz
1
upvoted, кстати, жаль, что OP не хочет вмешиваться, чтобы объяснить ...
wmz
8

Это даст вам список, а также поместит его в переменную с именем expanded_list. Поместите его в командный файл и запустите myBatchFile name myPattern. Заключите шаблон в кавычки, если он содержит пробелы. Совпадает с файлами, без каталогов. Запуск без параметров соответствует всем.

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

Затем вы можете запустить свою команду с my_command_exec %expanded_list%

ПРЕДУПРЕЖДЕНИЕ! Максимальный размер переменной cmd составляет 8191 символ (начиная с XP), поэтому его можно переполнить! Вы не можете рассчитывать на утилиту, чтобы всегда дать вам полный список. С другой стороны, максимальная длина строки cmd также равна 8191, поэтому вы не сможете выполнить ее в любом случае.

WMZ
источник
Обратите внимание, что если аргументы не указаны, то для параметра extended_list будут установлены все файлы в текущем каталоге, которые могут быть, а могут и не быть желаемыми, поэтому может потребоваться добавить проверку на отсутствие аргументов (например, если "% 1" == "" ...)
JasonM1
3

Это работает в cmd.exe

dir /b *.ext

или

echo | dir /b *.ext
user619818
источник
Это работает только для имени файла, а не какой-либо части пути. Например dir /b TortoiseSVN\bin\sv*.exeпокажет svn.exeи svnadmin.exe. Но dir /b TortoiseSVN\bi*\svn.exeпоказывает синтаксическую ошибку.
Styfle
1
проверить dir /s /b. Это дает вам полный путь.
WesternGun
3

Обратите внимание, это в комментариях к постерам в отдельной ветке user619818 и styfle)

DIR может и позволяет искать во всех подкаталогах файлы, соответствующие определенному типу.

Примечание. Предполагается, что корневым каталогом для проверки того, под какими каталогами находятся все подкаталоги, является «C: \ My Program \ Root \», поскольку автор не указал путь, по которому расположены эти каталоги.

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

это даст полные пути к файлам и имена файлов исходных файлов.

если вам нужны только имена файлов, вы должны сделать следующее

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

Итак, если вы хотите переместить все эти файлы из «C: \ My Program \ Root \ Sub Directories \ *. ext» в «D: \ Singlefolder \ *. ext», вы просто делаете это:

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

Надеюсь, что это поможет другим в будущем. :)

Бен Персоник
источник
1

Это старый, но с подсистемой Linux для Windows, довольно часто иметь bash в вашей переменной PATH. Если это так, то это может помочь вам:

bash -c 'cat *.txt'
Ричард
источник
обратите внимание, что одинарные кавычки не являются специальными в Windows cmd , поэтому, если вы запустите приведенную выше команду из cmd, она не будет работать. И это также относится к системам с Cygwin или другими средами bash
phuclv