Czy jest jakiś sposób na to, aby powłoka cmd systemu Windows rozszerzyła ścieżki symboli wieloznacznych?

37

Czasami niezdolność powłoki cmd do rozwinięcia ścieżek symboli wieloznacznych może być naprawdę niedogodnością. Musiałem przekazać programowi 100 plików z katalogu i nie mogłem wpisać * .ext. Zamiast tego użyłem „ls” mingw do zrzucenia listy do pliku, a następnie zastąpiłem znaki nowej linii spacjami, skopiowałem i wkleiłem do cmd. Całkiem koszmar.

Podejrzewam, że odpowiedź brzmi „nie”, ale czy ktoś sobie z tym poradził lub wymyślił sposób, aby to ułatwić?

kemulować
źródło
2
Czy zastanawiałeś się nad użyciem czegoś takiego jak PowerShell?
I suspect the answer will be no, but has anyone dealt with this or come up with any way to make this easier? W rzeczywistości mam odwrotny problem, próbuję wymyślić sposób, aby interpreter poleceń traktował listę jako ciągi znaków i zapobiegał interpretowaniu ich jako symboli wieloznacznych. Na przykład, for %i in (foobar baz really?) do @echo %ibędzie traktować ostatnią pozycję ( really?) jako zamiennika nazwy pliku, a pominąć, jeśli nie ma żadnych plików o nazwach really1, reallyzitp ☹
Synetech
1
@Synetech - ?nie jest znakiem prawnym dla nazw plików w systemie plików Windows. Postać można interpretować tylko jako symbol wieloznaczny. Zobacz Nazewnictwo plików, ścieżek i przestrzeni nazw w MSDN i Używanie symboli wieloznacznych w TechNet.
jww

Odpowiedzi:

18

DOS, a co za tym idzie Windows ' cmd.exe, nigdy nie wspierały rozszerzenia znaku wieloznacznego przez powłokę. Rozbudowa zawsze zależała od aplikacji.

Oznacza to, że zawsze będziesz musiał znaleźć inną trasę, jeśli korzystasz z aplikacji, która nie obsługuje rozszerzenia. Mógłbyś:

  • Użyj pętli FOR, aby uruchomić niektóre polecenia przeciwko wszystkim zainteresowanym plikom
  • Użyj, dir /b > list.txtaby użyć dirpolecenia, aby wykonać rozwinięcie i umieścić listę plików w pliku tekstowym (możesz użyć czegoś takiego jak formuła Excela, jeśli naprawdę desperacko chcesz stworzyć listę poleceń do wklejenia cmd, lub możesz użyć Excela do transponowania komórek, aby wszystkie nazwy plików znajdowały się w tej samej linii).
Malvineous
źródło
Wyjaśnił, że koszmarem byłoby umieszczanie wyników katalogu w pliku oraz ręczne filtrowanie i kopiowanie procesów. Odpowiedź wmz i oczywiście moja działałaby bez ręcznego filtrowania zawartości plików.
wullxz,
1
@wullxz: Być może, ale dla kogoś, kto nie zna Powershell, który chce zrobić to jednorazowo, może to być znacznie szybsze - a ideą tej witryny jest zapewnienie przydatnych rozwiązań dla osób na wszystkich poziomach umiejętności, do których można się odwoływać teraz i w przyszłość, więc naprawdę nie ma powodu, żeby mi to odpychać, ponieważ uważasz, że moja odpowiedź nie jest tak dobra jak twoja.
Malvineous
1
„DOS, a co za tym idzie cmd.exe systemu Windows, nigdy nie obsługiwał rozszerzenia znaku wieloznacznego przez powłokę.” - Nieprawda według Microsoft. Zobacz Używanie symboli wieloznacznych w TechNet. (Ale myślę, że masz rację w praktyce: o. W przeciwnym razie nie byłoby mnie tutaj, aby dowiedzieć się, dlaczego pliki nie są dopasowane)
jww
1
@jww: opublikowany link wyjaśnia standardowe użycie symboli wieloznacznych, ale nie widzę żadnej wzmianki o ich rozszerzaniu przez powłokę. W przeciwieństwie do UNIX (a później Linux i Mac), Microsoft pozostawił rozszerzenie symboli wieloznacznych do każdej aplikacji do wdrożenia, przekazując parametry wiersza poleceń bez zmian.
Malvineous
1
Polecenie DOS „dir Filespec / b” działa naprawdę dobrze, ponieważ tworzy listę plików, po jednym w wierszu. Dzięki dodatkowemu przełącznikowi „/ s” nazwy plików są w pełni kwalifikowane (bezwzględne) i mogą być łatwo przekazywane przez pętlę for do dowolnego innego programu wiersza poleceń, który przyjmuje nazwę pliku. To najlepsze, co możemy zrobić, ponieważ system Windows nie ma odpowiedniej funkcji globowania.
David A. Gray,
9

Wystarczy użyć programu Powershell, który jest wstępnie zainstalowany w systemie Windows 7. Powershell jest zdolny do uruchamiania poleceń cmd i rozumie symbole wieloznaczne w dowolnym miejscu na ścieżce.

Aby uruchomić PowerShell, po prostu wpisz „powershell” w polu wyszukiwania menu Start i naciśnij klawisz Enter.


Jeśli aplikacja oczekuje ciągu zawierającego wszystkie nazwy plików, jest to właściwy skrypt:

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

Zmiana $delimiter = " "do $delimiter = ","jeśli aplikacja oczekuje oddzielonych przecinkami listę nazw plików.

Objaśnienie kodu:

  • [string]$files = $nothing - tworzy pustą zmienną typu string
  • ; - jest separatorem dla wielu poleceń, a nie potokiem!
  • ls *.txt | % { $files += $_.fullname + $delimiter } - pobiera listę wszystkich plików tekstowych i tworzy ciąg ze wszystkimi nazwami plików oddzielonymi separatorem
  • application.exe $files - wywołuje aplikację i przekazuje do niej listę plików

Możesz nawet wyszukać wzorzec pliku rekurencyjnie, dodając -recursego, ls *.txtaby pełny kod wyglądał następująco:

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

Edycja:
Aby uniknąć podrażnienia, lsa dirsą aliasy Get-ChildItemi %jest aliasem ForEach-Object. Trzymam kod z używanymi aliasami, ponieważ jest on krótszy.

EDYCJA 2018/04/25:
W 2012 roku byłem całkiem nowy w PowerShell. Oczywiście istnieje łatwiejszy sposób, choć nie jest tak łatwy, jak możliwość globalnej ekspansji unix / linux:

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

Wyjaśnienie:

  • $ () najpierw oceni wyrażenie wewnątrz i zamieni się na dane wyjściowe tego wyrażenia (podobnie jak backticks w bash)
  • ls *.txt pobiera obiekty FileInfo wszystkich plików pasujących do globu *.txt
  • ponieważ PowerShell jest zorientowany obiektowo, musimy wypisywać pełną nazwę każdego obiektu FileInfo. Po prostu nazywanie atrybutu / właściwości w PowerShell generuje go domyślnie. % { $_.FileName }robi to dla nas. %zapętla wszystkie elementy zwracane przez lsi wypisuje każdy obiekt FileName.
wullxz
źródło
2
Chociaż PS z pewnością jest w stanie spełnić to wymaganie, a rada do zapoznania się z nim jest rozsądna - nie jest tak prosta, jak sugerujesz. Bieganie start notepad++ *.txt(z zamiarem, aby otworzyć wszystkie TextFiles - Używane Notepad ++ jak to robi obsługiwać wiele nazwisk) będzie Ci nigdzie
WMZ
1
Można to obejść za pomocą dir *.txt | % { notepad++.exe $_ }. Próbowałem tego z prostym notatnikiem, ponieważ nie mam notatnika ++ i zadziałało. Polecenie otrzymuje listę wszystkich plików txt w bieżącym katalogu, przekazuje listę do następnego polecenia, które przechodzi przez listę i wykonuje notatnik ++ z nazwą pliku jako parametrem.
wullxz
tak, ale to nie jest równoważne. Pomyśl o grep "a b c"znalezieniu dowolnego z wymienionych ciągów, w których „ab c” byłaby rozwiniętą listą
wmz
5
Uruchomienie polecenia z listą pozycji jako parametrem nie jest równoważne wielokrotnemu uruchomieniu polecenia z każdym elementem z listy jako parametru. Kolejny przykład: copy a+b+c resulti copy a result copy b result copy c result. (i narzędzie grep like istnieje w PS, nazywa się select-string)
wmz
1
przegłosowane, a przy tym szkoda, że ​​OP nie chce
wtrącać się
8

To da ci listę, a także umieści ją w zmiennej o nazwie expanded_list. Umieść go w pliku wsadowym i uruchom z myBatchFile name myPattern. Dołącz wzór ze znakami cudzysłowu, jeśli zawiera spacje. Dopasowuje pliki, bez katalogów. Uruchom bez parametrów pasuje do wszystkich.

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

Następnie możesz uruchomić polecenie za pomocą my_command_exec %expanded_list%

OSTRZEŻENIE! Maksymalny rozmiar zmiennej cmd wynosi 8191 znaków (XP i więcej), więc można ją przepełnić! Nie możesz liczyć na to, że narzędzie zawsze da ci pełną listę. Z drugiej strony maksymalna długość linii cmd wynosi również 8191, więc i tak nie będzie można jej wykonać.

wmz
źródło
Zauważ, że jeśli nie podano żadnych argumentów, lista rozwijana zostanie ustawiona na wszystkie pliki w bieżącym katalogu, które mogą, ale nie muszą być, więc może chcieć dodać sprawdzanie pod kątem braku argumentów (np. Jeśli „% 1” == ”„ ...)
JasonM1
3

Działa to w programie cmd.exe

dir /b *.ext

lub

echo | dir /b *.ext
użytkownik619818
źródło
Działa to tylko w przypadku nazwy pliku, a nie żadnej części ścieżki. Na przykład dir /b TortoiseSVN\bin\sv*.exepokaże svn.exei svnadmin.exe. Ale dir /b TortoiseSVN\bi*\svn.exepokazuje błąd składniowy.
styfle
1
sprawdzić dir /s /b. To daje ci pełną ścieżkę.
WesternGun
3

Uwaga: jest to w komentarzu do plakatów w osobnym wątku user619818 i styfle)

DIR może i pozwala przeszukiwać wszystkie podkatalogi w poszukiwaniu plików pasujących do określonego typu.

Uwaga: przyjmuje się, że katalog główny, w którym znajdują się wszystkie podkatalogi, to „C: \ Mój program \ Katalog główny”, ponieważ autor nie podał ścieżki, pod którą znajdują się te katalogi

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

da to pełne ścieżki do plików i nazwy plików źródłowych.

jeśli chcesz tylko nazwy plików, musisz wykonać następujące czynności

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

więc zakładając, że chcesz przenieść wszystkie te pliki z „C: \ My Program \ Root \ Sub Directories \ *. ext” do „D: \ Singlefolder \ *. ext”, po prostu wykonaj następujące czynności:

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

Mam nadzieję, że pomoże innym w przyszłości. :)

Ben Personick
źródło
1

Jest to stare, ale z podsystemem Linux dla Windows, dość powszechne jest teraz bash w PATH. W takim przypadku może to załatwić sprawę:

bash -c 'cat *.txt'
Richard
źródło
zauważ, że pojedyncze cudzysłowy nie są specjalne w cmd Windows , więc jeśli uruchomisz powyższe polecenie z cmd, to nie zadziała. Dotyczy to również systemów z Cygwin lub innymi środowiskami bash
phuclv