Can anyone explain what that expression is for and how to use it?

Asked

Viewed 148 times

-1

I would like to copy more recent files from one directory to another. But besides being the mais recente (data de criação) I have other conditions for copying:

  • Start with "Relatório Financeiro"

  • Files with the same name in different formats, one in .PDF another in .XLSX.

I came across this expression in the Super User community, but being a beginner did not have enough score to comment and ask for more clarification on the code snippet.

@Echo off
Set "Xnewest=2"
For /F "tokens=1* delims=:" %%A in (
  'Dir /B /A-D /O-D ^| Findstr /N "^"'
) Do If %%A Leq %Xnewest% echo Move "%%B" "X:\Path\to\dest\"

I’ve already done some research and I have a basic notion but I wonder if anyone could shed some light what that expression makes and as she does.

Any alternative to my first need is also welcome.

  • If the idea is to move only 1 pair of files (1 .pdf + 1 .xlsx) per run, hence the suggestion would be another.

  • @Itwasn'tme read your answer and you killed all my doubts regarding expression, I thank you too dear! I didn’t really insert in the question but I would like to copy only the most recent pair, I don’t know if it helps or if it makes a difference edit it, because you have already gone through all the work of writing me your answer, but I am very interested to know your suggestion. I’d need another question?

  • Your question already suggests the action involving the file pair and being recent, and as for the work/time demanded, understand that it is profitable result of isolation period treated as occupational therapy/recreational. ;-)

1 answer

3


  • Items of 1. to 5.:

I have already done some research and I have a basic notion but I wonder if anyone could clarify what this expression does and how it does.

  • Items of 6. to 9.:

...copy more recent files from one directory to another. But besides being the latest (creation date) I have other conditions for copying:

  • Start with "Financial Report"

  • Files with the same name in different formats, one in . PDF another in . XLSX.

  • Items 10. and 11. [move only 1 pair of files (1 .pdf + 1 .xlsx) per run]:

..but I would like to copy only the most recent pair...


1. Execution of the command Dir /B /A-D /O-D will result in the listing of items in the current folder, where this output will return only the filenames in a form "basic", a simple nome-de-arquivo.extensão and also not listing the drive:\caminho\completo\para\nome-de-arquivo.extensão

Dir            // lista arquvivos e pastas no Diretorio atual
Dir /B         // lista arquvivos e pastas na forma Básica, sem drive/caminho completo
Dir /A-D       // lista arquivos apenas, por excluir os itens com Atributo de Diretório,
               // observe que o "-" significa exclir o item, como em:

                  /A-D <==> -Diretórios <==> liste os itens, menos com Atributo -Diretórios
                  /A-A <==> -Arquivos   <==> liste os itens, menos com Atributo -Arquivos

               // observe que sem o "-" significa restringir/limitar ao item, como em:

                  /AD <==> Diretórios <==> liste os itens com Atributo Diretórios
                  /AA <==> Arquivos   <==> liste os itens com Atributo Arquivos

Dir /O-D       // lista arquivos em uma dada Ordem, nesse caso, por Data
               // observe que o "-" aqui vai significar uma inversão da ordenação padrão: 

                  /OD  <==> Ordenar por Data <==> liste do mais antigo para o mais recente/novo
                  /O-D <==> Ordenar por Data <==> liste do mais recente/novo para o mais antigo

Dir/B/A-D/O-D  // liste os nome de arquivos, exclindo os caminho/pastas, na ordem
               // inversa, por data de modificação/data de criação (o que for mais recente).
  • Results:
> Dir /B /A-D /O-D
Q99999.txt
A99999.txt
Q99999.cmd
I99999.png

2. The redirect made by the operator "|" out of command dir is handled in command Findstr, and this will result in a listing Nmoistened from all lines resulting from the execution of the previous command, dir.

Dir/B/A-D/O-D  // liste arquivos na ordem inversa de data de modificação/criação (mais recente).
^              // o escaping para o uso do pipe "|", que é necessário no for/f ('^|')
|              // redireciona a saída do comando anterior (Dir/B/A-D/O-D) para o Findstr
Findstr /N "^" // vai listar a saída obtida no comando anterior, Númerando todas as linhas.
  • Results:
> Dir /B /A-D /O-D | Findstr /N "^"
1:Q99999.txt
2:A99999.txt
3:Q99999.cmd
4:I99999.png

3. The command For /F loop will create a loop to manipulate the actions resulting from the commands Dir/B..| Findstr.., capturing the output to make use of these separating them in a predefined way, to meet in its delimiter (delims=:) defined, and the elements of the first occurrences (tokens= [1] ), and all (*) the elements of the second occurrence until last occurrence (tokens=1-[*] ).

  • For any element/string that appears before the delimiter ":" (in the first occurrence of the delimiter), will be treated in the loop variable %%A, and all occurrences after the first occurrence, ie all occurrences/strings after %%A, will be treated in the loop variable %%B
[ comando  em  loop]                  [ sáida  em  loop ]
Dir /B /A-D /O-D | Findstr /N "^"       1:Q99999.txt

<elemento %%A > [delimitador] <elemento(s) %%B>
      1               :          Q99999.txt
      2               :          A99999.txt
      3               :          Q99999.cmd
      4               :          I99999.png

4. To explain the actions of this batch/batch code, I will remove (explaining), which is not necessary (or dispensable):

@Echo off
Set "Xnewest=2" // define uma variavél atribuindo o numero 2 como valor
For /F "tokens=1* delims=:" %%A in (
'Dir /B /A-D /O-D ^| Findstr /N "^"'
) Do If %%A Leq %Xnewest%    echo  Move "%%B" "X:\Path\to\dest\"
             // 2            ecoe  Move "%%B" "X:\Path\to\dest\"
             // 2 imprima na tela  Move "%%B" "X:\Path\to\dest\"
  • For each item obtained from the outputs resulting from the listing of the control Dir..| Findstr, take %%A, which is the number that has been assigned to the current command output line Dir for Findstr, and if that line number is equal Equ or less Lss (Equ [or] Lss <==> Leq), echo/print the command Move...
  • The command echo Move.. will only allow a check of the output of the processed loop, so that the author of the code, or the author of the question, has the possibility to check whether the files where the command actually occurs, satisfies the condition in the proposed objective, where it is observed that:
                [Dir] Liste arquivos dos mais recentes aos mais antigos e apenas nomes
            [Findstr] Enumere as linhas dessa saída, na forma, "numero" + ":" + "nome.extensão"
[For + if (%%A ≦ 2)] Se número da linha é menor ou igual a 2, mova item %%B para drive:\pasta\

5. Components that must satisfy/observe to make this loop/bat effective:

  • the bat is running in the same folder where the files are being "manipulated" in loop
  • the running bat is either older or has its modification/editing prior to the loop files

6. Considering the utility/application of the commented code, and making a suggestion to limit its action in only the two files .pdf, and .xlsx more recent, with the name starting in "Financial Report":

@echo off && cd/d "z:\Pasta\de\Origem\" 

for %%i in (xlsx pdf)do for /F tokens^=1*delims^=: %%A in (
     'dir/b/a-d/o-d .\"Relat?rio Financeiro*.%%~i"^|findstr/n .
     ')do if %%~A leq 2 echo=move /y ".\%%~B" "x:\Pasta\de\Destino\."
  • Same code/result in version with conventional layout:
@echo off 

cd /d "F:\Pasta\Origem"

for %%i in (xlsx,pdf) do ( 
     for /F "tokens=1* delims=:" %%A in ('dir /b /a:-d /o:-d .\"Relat?rio Financeiro*.%%~i" ^| findstr /n .') do (
         if %%~A leq 2 echo=move /y ".\%%~B" "X:\Pasta\de\Destino\."
        )
    )

7. In the suggested item 6., I’m replicating the command echo enabling the execution in tests/checks, after that, just remove the echo= for the effective movement of files.

@echo off && cd/d "z:\Pasta\de\Origem\" 

for %%i in (xlsx pdf)do for /F tokens^=1*^delims^=: %%A in (
     'dir/b/a-d/o-d .\"Relat?rio Financeiro*.%%~i"^|findstr/n .
     ')do if %%~A leq 2 move /y ".\%%~B" "x:\Pasta\de\Destino\."
  • Same code/result in version with conventional layout:
@echo off 

cd /d "F:\Pasta\Origem"

for %%i in (xlsx,pdf) do ( 
     for /F "tokens=1* delims=:" %%A in ('dir /b /a:-d /o:-d .\"Relat?rio Financeiro*.%%~i" ^| findstr /n .') do (
         if %%~A leq 2 move /y ".\%%~B" "X:\Pasta\de\Destino\."
        )
    )

8. To move files with the same names and different extensions, applying the order by modification/creation date (whichever is more recent), applying to the files .pdf and also mesmos_nome.xlsx:

@echo off && cd/d "z:\Pasta\de\Origem\" 

for /F tokens^=1*delims^=: %%A in ('dir/b/a-d/o-d/tc .\"Relat?rio Financeiro*.xlsx"^|findstr/n .
   ')do if %%~A leq 2 for %%i in (.pdf,%%~xB)do move /y ".\%%~nB%%~i" "x:\Pasta\de\Destino\."
  • Same code/result in version with conventional layout:
@echo off

cd /d "z:\Pasta\de\Origem\" 

for /f "tokens=1* delims=:" %%A in ('dir /b /a:-d /o:-d /t:c .\"Relat?rio Financeiro*.xlsx" ^| findstr /n .') do (
     if %%~A leq 2 for %%i in (.pdf,%%~xB) do move /y ".\%%~nB%%~i" "x:\Pasta\de\Destino\."
    )

9. To apply the results only to files where the listing is in order of creation date (no modification), just add /TC

@echo off && cd/d "z:\Pasta\de\Origem\" 

for /F tokens^=1*delims^=: %%A in ('dir/b/a-d//o-d/tc .\"Relat?rio Financeiro*.xlsx"^|findstr/n .
   ')do if %%~A leq 2 for %%i in (.pdf,%%~xB)do move /y ".\%%~nB%%~i" "x:\Pasta\de\Destino\."
  • Same code/result in version with conventional layout:
@echo off

cd /d "z:\Pasta\de\Origem\" 

for /f "tokens=1* delims=:" %%A in ('dir /b /a:-d /t:c .\"Relat?rio Financeiro*.xlsx" ^| findstr /n .') do (
     if %%~A leq 2 for %%i in (.pdf,%%~xB) do move /y ".\%%~nB%%~i" "x:\Pasta\de\Destino\."
    )

10. To get the latest file, whether it is this one .pdf or a .xlsx, and use the same name for (the most recent file) and move it in "par", (.xlsx + .pdf or .pdf + .xlsx) to another folder:

@echo off && cd /d "z:\Pasta\de\Origem\"

for /f tokens^=* %%i in (
    'dir/b/a-d/o-d/tc .\"Relat?rio Financeiro*.*"^|%__AppDir__%findstr.exe/eli "\.pdf \.xlsx"')do (
         move /y ".\%%~nxi" "x:\Pasta\de\Destino\." && if /i "%%~xi" == ".xlsx" >nul (
             move /y ".\%%~ni.xlsx" "x:\Pasta\de\Destino\." ) else >nul (
                 move /y ".\%%~ni.pdf" "x:\Pasta\de\Destino\.")
                    ) & goto :eOf
Dir/B/A-D/O-D/TC  // liste arquivos na ordem inversa de data (criação)
^                 // o escaping para o uso do pipe "|", que é necessário no for/f ('^|')
|                 // redireciona a saída do comando anterior (Dir/B/A-D/O-D/T:C) para o Findstr
Findstr/ELI       // obtem no comando anterior, arquivos que terminam (End) Literalmente Insensitivo
"\.pdf \.xlsx"    // obtem as linhas que terminarem Literalmente com ".pdf" ou ".xlsx" caso 
                  // Lnsensitivo (independente de caixa alta ou baixa)
               
                  // observe que o "\." é diferente de ".", onde sem o uso do "escape" \, vai 
                  // significar para o Findstr "qualquer caratere", mas já o \. vai sinalizar
                  // Literalmente "." o ponto, assim resultando nas extensões "."+pdf e/ou ".xlsx"

if /i             // uso do if em condição de comparação de caso Iinsensitivo  
"%%~xi"==".xlsx"  // se a eXtensão ("%%~xi") do arquivo em loop for igual ".xlsx", ele move tambémm
                  // o arquivo com o mesmo Nome + eXtensão ".pdf" par a pasta de destino, caso o 
                  // contrario aconteça, o arquivo ".pdf" é o mais velho dentro do loop, vai 
                  // inverter a ação, movendo primeiro o .pdf, e depois o arquvo de mesmo nome .xlsx

Goto :eOf         // como a primeiro laço/loop já foi excutado, o par também já foi movido, e 
                  // entendendo que os outros arquivos do loop não são mais necessários, então 
                  // aborta-se a execução do loop/processamento, movendo a execução do batch 
                  // para o final do arquivo (Goto End Of File)

11. Case in your files, the extension ".pdf" are always the latest, and need only set the action so that it is based on that extension to get the file name "par" in "xlsx", or the other way around, by inverting ". pdf"/". xlsx", the sap suggestion:

@echo off

cd/d "z:\Pasta\de\Origem\"

for /f tokens^=* %%i in ('
    dir/b/a-d/o-d/tc .\"Relat?rio Financeiro*.pdf"')do >nul (
     move /y ".\%%~ni.xlsx" "x:\Pasta\de\Destino\."
     move /y ".\%%~nxi" "x:\Pasta\de\Destino\."
     goto :eOf
    )

Additional explanations about for /f, skip, tokens and delims:

Some references for consultation/support in /English:

  • Thanks for the answer! I had just one difficulty in making it work by creation date. For some reason it works with modification date and not with creation date. Using conventional structure I just changed dir /b /a:-d /o:-d for dir /b /a:-d /t:-c and stopped working.

  • @sena has no "inverse" use option with - in -C to the flag /T, just add the TC: Dir /B/A-D/O-D/TC

  • Our guy, this code is awesome, congratulations!

  • Just out of curiosity, is there any limitation regarding using paths that are shared folders? Testing location it was perfect. When I changed the destination and source from where the files would be copied to directory addresses on the server, it did not complete the transfer. Thank you so much for your time, I have learned a lot!

  • @Sena would be the case to replace the move by copy, or by Robocopy, or can still try to assign a unit (subst or net use ...) to the remote location, then change to copy to that "virtual" unit pointed to the remote folder. Thank you to Voce tbm for reading, testing, etc...

  • Replaced by copy to make a test. I tried it too net use x: "\\servidor\" but it wasn’t. In the next few days I’m going to touch more on this code, I’m not sure if my syntax is correct.

  • @sena it would be easier to use the copy and then delete the files at source.

  • @if I don’t have a way to test, but use + path; move /y ".\%%~ni.pdf" \\\\remoto\

  • 1

    @sena see this one reply and the above suggestion.

  • Thank you, I’ll try them on!

Show 5 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.