Para em lote tem comportamento estranho ao ler pastas

1

Estou tentando fazer um lote simples (não é a coisa toda, mas essa é a parte que está fazendo tudo falhar)

@echo off
for /f "tokens=*" %%G in ('dir /s /b /a:d "e:\tmp\*"') do (
    echo %%G
    set fullpath=%%G
    set basename=%fullpath:~7%
    echo %fullpath%
    echo %basename%
)

Este script deve ser executado em todos os lugares, portanto, o loop for funny. É suposto olhar pelo diretório e fazer algumas coisas.

Neste diretório específico, há outros três diretórios: bomslenovodb , cpat e finance

O resultado esperado

e:\tmp\bomslenovodb
e:\tmp\bomslenovodb
bomslenovodb
e:\tmp\cpat
e:\tmp\cpat
cpat
e:\tmp\finance
e:\tmp\finance
finance

A saída real

First run
e:\tmp\bomslenovodb
ECHO is off.
ECHO is off.
e:\tmp\bomslenovodb
e:\tmp\cpat
ECHO is off.
ECHO is off.
e:\tmp\cpat
e:\tmp\finance
Second run
ECHO is off.
ECHO is off.
e:\tmp\finance
e:\tmp\bomslenovodb
e:\tmp\finance
ECHO is off.
e:\tmp\bomslenovodb
e:\tmp\cpat
e:\tmp\finance
Third run
ECHO is off.
e:\tmp\cpat
e:\tmp\finance
e:\tmp\finance
ECHO is off.
e:\tmp\finance
e:\tmp\bomslenovodb
e:\tmp\finance
e:\tmp\finance
Fourth run
e:\tmp\bomslenovodb
e:\tmp\cpat
e:\tmp\finance
e:\tmp\finance
e:\tmp\cpat
e:\tmp\finance
e:\tmp\finance
e:\tmp\finance
e:\tmp\finance

Parece-me que o set fullpath=%%G não está se comportando como deveria, então o valor não está definido corretamente.

Eu estou em uma máquina com Windows Server 2008, alguma idéia?

    
por Hito_kun 07.05.2014 / 23:45

1 resposta

5

Erro de lote clássico: -)

O comando SET está funcionando bem. É a sua expansão que está falhando.

A expansão

%VAR% ocorre quando a instrução é analisada e todos os comandos dentro do loop FOR são analisados de uma só vez. O mesmo é verdadeiro para qualquer bloco de código entre parênteses. Portanto, os valores de %fullpath% e %basename% são constantes durante a execução do loop FOR - os valores que existiam antes da inserção do loop (indefinido nesse caso).

A correção é usar a expansão atrasada, que ocorre imediatamente antes do comando ser executado. A expansão atrasada deve ser ativada com setlocal enableDelayedExpansion antes de poder ser usada. E a sintaxe da expansão muda para !VAR! .

@echo off
setlocal enableDelayedExpansion
for /f "tokens=*" %%G in ('dir /s /b /a:d "e:\tmp\*"') do (
    echo %%G
    set fullpath=%%G
    set basename=!fullpath:~7!
    echo !fullpath!
    echo !basename!
)

Mas ainda há um problema em potencial. Os nomes dos arquivos podem conter o caractere ! e qualquer variável FOR contendo ! será corrompida na expansão quando a expansão atrasada estiver ativada. A solução é ativar e desativar a expansão atrasada dentro do loop.

@echo off
for /f "tokens=*" %%G in ('dir /s /b /a:d "e:\tmp\*"') do (
    echo %%G
    set fullpath=%%G
    setlocal enableDelayedExpansion
    set basename=!fullpath:~7!
    echo !fullpath!
    echo !basename!
    endlocal
)

Se você precisar proteger ! literais e precisar das atribuições de variáveis para persistir entre as iterações, a melhor coisa a fazer é usar um procedimento CALLed para que você possa usar a expansão normal. Simplesmente transfira o valor da variável FOR para um parâmetro CALL. Mas usar CALL é significativamente mais lento do que colocar tudo diretamente no loop.

@echo off
for /f "tokens=*" %%G in ('dir /s /b /a:d "e:\tmp\*"') do call :proc "%%G"
exit /b

:proc
echo %~1
set "fullpath=%~1"
set "basename=%fullpath:~7%"
echo %fullpath%
echo %basename%
exit /b
    
por 08.05.2014 / 00:10