0

I'm trying to create a list of files created yesterday.

I've got the below working without /c:"cmd /c echo @path" but I want the full path.

forfiles /s /d -1 /m *.txt /c:"cmd /c echo @path" > a.txt
forfiles /s /m *.txt /c:"cmd /c echo @path" > b.txt
FOR /f "delims=; tokens=*" %%X IN ('findstr /v /g:a.txt b.txt') DO (
    echo %%X
)

What is the best way to get around the issue with using findstr with a path containing backslashes? Do I need to replace all the backslashes in the comparison files with some other symbol and then change it back later or is there an easier way to do it in the findstr line?

tivrick
  • 3
  • 2
  • can you edit your question to show an example of your expected output? everything in your block is working as it should as far as I can understand your question. – mael' Jul 22 '19 at 14:35
  • 2
    Use also `findstr` option `/L` to get the file names in `a.txt` interpreted as literal strings and not as regular expression strings. And I recommend to use also `findstr` option `/X`. Open a command prompt window and run `findstr /?` for an explanation of these two options. – Mofi Jul 22 '19 at 15:24
  • The __FOR__ loop is not really necessary. But if you need it nevertheless, the `for /F` options should be better `"eol=| delims="` to get the file names with full path always completely assigned to specified loop variable `X`. It would be also better to use a different loop variable like `I`, `J` or `#`. Run in a command prompt window `for /?` and read the output help, especially the section about modifiers like `%~xI` which could be also written as `%~XI` with loop variable being `I` and you know why it is better not using `x` or `X` as loop variable. – Mofi Jul 22 '19 at 15:30
  • If you're `trying to create a list of files created yesterday`, you should be aware that the `ForFiles` option, `/D`, selects items with a **last modified** date and is therefore of no use to you. – Compo Jul 22 '19 at 15:59
  • Isn't the colon in `forfiles ... /c:"..."` a typo? – aschipfl Jul 22 '19 at 19:06
  • When you use the `/L` option of `findstr` most problems should be solved. However, a dir. or file beginning with `[`, `]` and `.` are still problematic since these meta-characters are still recogniaed by `findstr` (although there is no `/R`!) and hence the preceding backslash becomes removed due to escaping; I guess the only way to handle even such names correctly in to double any backslashes in the file specified after `/G:`. By the way, also add the `/I` option as dir. and file names are treated case-insensitively by Windows, and to avoid a strange `findstr` issue with literal search strings – aschipfl Jul 22 '19 at 19:17

2 Answers2

0

I prefer for such tasks:

Get-ChildItem -Path "C:\Users\tivrick" -Recurse -ErrorAction SilentlyContinue | Where-Object { -Not $_.PSIsContainer -And $_.CreationTime.Date -Eq (Get-Date).Date.AddDays(-1) } | Select-Object -ExpandProperty FullName

If you really need to run that from a :

@PowerShell -NoP "GCI "C:\Users\tivrick" -R -EA SilentlyContinue|?{!$_.PSIsContainer -And $_.CreationTime.Date -Eq (Get-Date).Date.AddDays(-1)}|Select -Exp FullName"
Compo
  • 36,585
  • 5
  • 27
  • 39
0

The findstr command checks the very first search expression and changes to regular expression mode when a meta-character is found or to literal mode otherwise, unless you explicitly predefine the mode by /L (literal) or /R (regular expression).

But findstr is a nasty beast since there are still some problems even with /L:

  • wrong results may be returned with multiple literal search strings, unless you specify /I to do case-insensitive searches; but this is not a problem here anyway since you are dealing with directory and file names, which are treated case-insensitively by Windows anyway;
  • although in literal mode, escaping of meta-characters like ., [, ], ^, $, \, * and ? still occurs when there is a \ in front; you could just double all \ to work around that;

So the following code should work in most situations; delayed expansion is enabled herein by cmd /V, which is required to read the interim variable FILE that is written and read in the same command line:

forfiles /S /M "*.txt" /D -1 /C "cmd /C if @isdir==FALSE (set FILE=@path) & cmd /V /C echo(!FILE:\=\\!" > "exclude.txt"
forfiles /S /M "*.txt"       /C "cmd /C if @isdir==FALSE echo @path" > "all.txt"
for /F "delims=" %%X in ('findstr /V /L /I /X /G:"exclude.txt" "all.txt"') do (
    echo(%%X
)

I inserted if @isdir==FALSE here to not match directories whose names end in .txt. Also I added /X to findstr in order to match whole lines/paths only.

Regard that literal findstr search strings are limited to a length of 511 bytes (after doubling \), which can easily be reached with file paths.


However, what about a different approach that avoids findstr at all?

Here is a post I once provided for returning items newer than a relative date with forfiles: FORFILES date -after- (date calc in cmd file).

aschipfl
  • 33,626
  • 12
  • 54
  • 99