O script em lote de várias linhas convertido em comando de linha única retorna resultados diferentes dos originais

1

Estou tentando transformar o script de várias linhas

@echo off

for /f "eol=: delims=" %%D in ('dir /b /s /ad *^|sort /r') do (
  pushd "%%D"
  for %%F in (*) do move "%%F" "..\%%~nxD - %%F" >nul
  popd
  rd /s /q "%%D"
)
exit

para uma única linha, a fim de registrá-lo como uma entrada do menu de contexto. No meu entender, o comando de linha única equivalente seria este:

@echo off && for /f "eol=: delims=" %%D in ('dir /b /s /ad *^|sort /r') do (pushd "%%D" && for %%F in (*) do move "%%F" "..\%%~nxD - %%F" >nul && popd && rd /s /q "%%D") && exit

... mas produz resultados diferentes do script original.

Substituir & & com & produz um terceiro resultado diferente, mas, até onde sei, ainda precisaria do & & de qualquer maneira neste caso.

O que eu poderia estar fazendo de errado?

    
por Jesús Cruz 05.08.2017 / 00:18

1 resposta

1

Acontece que for … do é "ganancioso". (Eu não me lembro de saber isso antes, e não parece estar documentado de forma proeminente em for /? .

Eis o que quero dizer:

Considere o script cow1.bat :

@echo off
for %%a in (how now brown) do echo %%a
echo cow

Bastante trivial. Quando executado, gera

how
now
brown
cow

como podemos imaginar.

Considere o script cow2.bat :

@echo off
for %%a in (how now brown) do echo %%a & echo cow

O mesmo, exceto que as linhas 2 e 3 foram unidas, delimitadas por & . Adivinha!? Quando executado, gera

how
cow
now
cow
brown
cow

Ele está sendo interpretado como se fosse

@echo off
for %%a in (how now brown) do (echo %%a & echo cow)

(A alteração de & para && não teve efeito.) Em uma (para mim) maior surpresa,

@echo off
for %%a in (how now brown) do (echo %%a) & echo cow

também funcionou da mesma forma que cow2 . Eu tive que usar

@echo off
(for %%a in (how now brown) do echo %%a) & echo cow

para obter o comportamento original cow1 .

Como isso afeta o OP?

for %%F in (*) do move "%%F" "..\%%~nxD - %%F" >nul && popd && rd /s /q "%%D"

é análogo a cow2 : Se %%D (o diretório em que apenas pushd ’foi inserido) for beatles , então o segmento de código acima faz isso:

move "george" "..\beatles - george" >nul    &&    popd    &&    rd /s /q "beatles"
move "john"   "..\beatles - john"   >nul    &&    popd    &&    rd /s /q "beatles"
move "paul"   "..\beatles - paul"   >nul    &&    popd    &&    rd /s /q "beatles"
move "ringo"  "..\beatles - ringo"  >nul    &&    popd    &&    rd /s /q "beatles"

(espaço em branco adicionado para maior clareza). Então, está movendo o primeiro arquivo ( george ), e depois popd ’do diretório beatles e excluindo-o, deixando os outros arquivos para serem coletados pelo roomba.

Recomendação (TL; DR)

Tente

for /f "eol=: delims=" %%D in ('dir /b /s /ad *^|sort /r') do (pushd "%%D" && (for %%F in (*) do move "%%F" "..\%%~nxD - %%F" >nul) && popd && rd /s /q "%%D")
                                                                              ↑                                                   ↑

Questão Trivial:

Por que precisamos do * no subcomando dir /b /s /ad * ?

    
por 05.08.2017 / 09:24