Dir canalizado para Set

Dir canalizado para Set

Estou tentando fazer um programa que selecione um nome de arquivo e depois o canalize para uma variável.

Minha tentativa:

Dir /B "C:\Program Files (x86)\ServerMaster\Internals\Versions\Van1" | (set /p myVar= & set myVar)

Depois de usado ele dá

myVar:1.14.4

o plano era entrar e ecoar o comando, então fiz assim

@echo off
Dir /B "C:\Program Files (x86)\ServerMaster\Internals\Versions\Van1" | (set /p myVar= & set myVar)
echo e %myVar%
cmd /k

mas tudo o que acontece é

e

O que estou fazendo de errado? Além disso, existe uma maneira de fazer isso com FOR?

Responder1

O que estou fazendo de errado?

Simples - você está tentando usar uma técnica que não funciona ;-) É impossível usar a saída de comando canalizada para definir variáveis ​​de ambiente em seu ambiente pai devido à maneira como os pipes do Windows funcionam.

Seu script está sendo executado em um processo de comando - vamos chamá-lo de pai.

Um pipe do Windows inicia dois processos de comando filho, cada um com seu próprio espaço de ambiente separado. O lado esquerdo do tubo é executado no primeiro filho e o direito no segundo. O pipe envia a saída do primeiro filho como entrada para o segundo filho. O SET /Pdefine com sucesso a nova variável myVar no processo filho e o SET MYVARcomando exibe o valor. Ótimo.

Mas então o canal termina e ambos os processos filhos são encerrados e seus ambientes associados desaparecem. Não há como transferir o valor do ambiente myVar do processo de pipe filho de volta para o ambiente pai.

Existem muitos efeitos colaterais surpreendentes no design do pipe do Windows que confundem qualquer pessoa que não entenda completamente o mecanismo. Verhttps://stackoverflow.com/q/8192318/1012053para mais informações. Recomendo a leitura da pergunta e de todas as respostas.

Existe uma maneira de fazer isso com FOR?

Sim, a maneira correta de capturar a saída de um comando em uma variável de ambiente é via FOR, especificamente FOR /Fcomo mostra DavidPostill. Embora haja um problema definido, um problema potencial e uma ineficiência em seu código.

Não há necessidade de usar USEBACKQao processar a saída de um comando. É mais simples usar aspas simples regulares 'em vez de crase:for /f %%F in ('yourCommand') do ...

O erro é o uso de echo myVar:%myVar%dentro do corpo do loop FOR. Isso exibirá o valor myVarque existia antes da execução do loop porque a expansão percentual ocorre quando a linha é analisada e todo o loop FOR é analisado em uma única etapa. Você precisaria ativar a expansão atrasada ( setlocal enableDelayedExpansion) e depois usar echo !myVar!para ver o valor que foi definido dentro do loop.

Existe a possibilidade de outro problema - FOR /F analisará o valor em tokens delimitados por espaço e capturará apenas o primeiro token. Se o nome do seu arquivo contiver espaços, você não obterá o nome completo, a menos que use a opção DELIMS para não especificar nenhum delimitador.

for /f "delims=" %%F in (....) do .... 

Mas não há necessidade de usar DIR /Be FOR /F. Você pode simplesmente usar um FORloop vanilla sem a /Fopção.

Por exemplo, o seguinte irá simplesmente listar todos os arquivos:

for %%F in ("C:\Program Files (x86)\ServerMaster\Internals\Versions\Van1\*") do echo %%~nxF

Especifica o ~nxuso apenas do nome e da extensão do arquivo, descartando a unidade e o caminho da pasta.

Normalmente não há necessidade de usar uma variável de ambiente - basta usar a %%Fvariável FOR dentro do seu loop para fazer seu trabalho.

Mas se você precisar de um valor fora do loop por algum motivo, certamente poderá fazer

for %%F in ("C:\Program Files (x86)\ServerMaster\Internals\Versions\Van1\*") do set "myVar=%%~nxF"

Mas isso capturará apenas o último arquivo iterado. A variável myVar será substituída a cada iteração. Seu design original teria capturado o primeiro arquivo listado (supondo que ele pudesse funcionar). Nenhuma das duas parece uma boa ideia, a menos que você saiba com certeza que a pasta Van1 contém apenas um único arquivo.

Se você precisar capturar todos os arquivos em variáveis, precisará usar um pseudo array. O lote não possui um conceito formal de array, mas pode ser facilmente emulado. Você pode encontrar muitos exemplos se simplesmente pesquisar na web por "matriz de arquivos em lote"

informação relacionada