PDA

Показать полную графическую версию : [решено] Удалить файлы по спискам, содержащимся в нескольких *.lst


dassen
05-01-2019, 02:07
В папке MainFldr (и во вложенных в нее подпапках) нужно удалить (лучше в корзину) файлы по спискам, содержащимся во всех *.lst из папки LstFldr.
Другими словами:
В папке LstFldr есть несколько десятков *.lst , каждый из которых содержит список файлов, подлежащих удалению (ФПУ) из папки MainFldr (и из вложенных в нее подпапок).
Других файлов в папке LstFldr нет.
В *.lst имена ФПУ представлены без адресов; по одному на строку (пустых и посторонних строк нет), могут повторяться в различных *.lst.
Все ФПУ только с цифрами и EN-буквами в именах, с расширениями.
ФПУ (и/или содежащие их папки) могут быть с атрибутами +H, +S, +R.
ФПУ могут повторяться в папке MainFldr (и во вложенных в нее подпапках).
Хотелось бы также вывести в файл Deleted.lst список удаленных файлов (с их полными адресами до удаления),
а в файл NonDeleted.lst вывести список ФПУ, которые так и не удалились (с их полными адресами).
(OS: WinXP SP3)

Iska
05-01-2019, 03:01
есть несколько десятков *.lst , каждый из которых содержит список файлов »
Упакуйте несколько таких файлов в архив, каковой приложите к сообщению.

без адресов; »
В переводе на русский — без путей?

Хотелось бы также вывести в файл Deleted.lst список удаленных файлов (с их полными адресами до удаления), »
Возни больше, чем нужно (особенно для пакетных файлов).

dassen
05-01-2019, 04:24
смоделировал ситуацию как-то так

Iska
05-01-2019, 07:50
На PowerShell это может выглядеть, например, так:
$sListFolder = 'C:\Мои проекты\0235\SomethingLikeThis\LstFldr'
$sSourceFolder = 'C:\Мои проекты\0235\SomethingLikeThis\MainFldr'

if([System.IO.Directory]::Exists($sListFolder)) {
if([System.IO.Directory]::Exists($sSourceFolder)) {
$hFiles = @{}

Get-ChildItem -Path $sListFolder -Filter '*.lst' -File |`
ForEach-Object -Process {
Write-Host "Reading file name(s) from [$($_.FullName)]…" -ForegroundColor Cyan

Get-Content -Path $_.FullName |`
ForEach-Object -Process {
if(-not $hFiles.ContainsKey($_)) {
Write-Host "`tAdding unique file name [$_]" -ForegroundColor White
$hFiles.Add($_, $_)
} else {
Write-Host "`tDuplicate file name [$_] found, skipping" -ForegroundColor Gray
}
}
}
Write-Host "Total found $($hFiles.Count) unique file name(s).`r`n" -ForegroundColor Cyan

if($hFiles.Count -gt 0) {
Write-Host "Deleting file(s)…" -ForegroundColor Cyan

Set-Content -Path "Deleted.lst" -Encoding Default -Value '' -NoNewline
Set-Content -Path "NonDeleted.lst" -Encoding Default -Value '' -NoNewline

Get-ChildItem -Path $sSourceFolder -Include $($hFiles.Keys) -File -Recurse -Force |`
ForEach-Object -Process {
$sFullFileName = $_.FullName

Write-Host "`t$sFullFileName" -ForegroundColor White

try {
$_.Attributes = [System.IO.FileAttributes]::Normal
$_.Delete()
Add-Content -Path "Deleted.lst" -Encoding Default -Value $sFullFileName
} catch {
Write-Host "`t`tAn error occured while deleting file [$sFullFileName]" -ForegroundColor Red
Add-Content -Path "NonDeleted.lst" -Encoding Default -Value $sFullFileName
}
}
} else {
Write-Host "Nothing to delete." -ForegroundColor Cyan
}
} else {
Write-Host "Can't find source folder [$sSourceFolder]." -ForegroundColor Red
}
} else {
Write-Host "Can't find list's folder [$sListFolder]." -ForegroundColor Red
}

Busla
05-01-2019, 14:50
Iska, передать весь список искомых файлов через Include в Get-ChildItem - интересная идея - я её не думал - возьму на заметку. Спасибо.
P.S. ну и традиционное про лютый трэш и угар:
если вы раскрашиваете сообщения исходя из их разной ценности - используете стандартные Write-Debug, Write-Verbose, Write-Info - они и сами раскрасят, и ими можно извне хоть как-то управлять
но вообще, это бесполезное самолюбование - как в кино: по экрану бежит куча текста который никто не читает и в принципе не в состоянии прочитать и проанализировать. Лучше бы уж тогда Write-Progress впилили
заворачивать всё в глобальные if - ну так себе подход неудобно отслеживать к чему относится закрывающая скобка и else - разверните условие и сделайте выход сразу после if
.Net библиотеки не знают ничего про PSdisk, поэтому ваши скритпы невозможно тестировать стандартным Pester
метод файлового объекта Delete() вместо Remove-Item - тоже та ещё засада - я не могу в начале скрипта к примеру написать $PSDefaultParameterValues.Add("Remove-Item:WhatIf",$True) и посмотреть: что же происходит

YuS_2
05-01-2019, 15:35
...
Get-ChildItem ... -File
...»
OS WinXP SP3, выше PoSh v 2.0, увы не прыгнуть...

megaloman
05-01-2019, 15:43
@Echo Off
cls
Set "BoxData=Z:\Box_In\SomethingLikeThis\MainFldr"
Set "FileList=Z:\Box_In\SomethingLikeThis\LstFldr\*.lst"

Set /A N=10000
FOR %%f IN (%FileList%) DO FOR /F "usebackq delims=" %%s IN (`More "%%f"`) DO Call :Count "%%~nxs"

If %N%==%Max% Echo !!! "%FileList%" not found &Exit /B 2

Call :MyDel "%BoxData%"
FOR /F "usebackq delims=" %%d IN (`2^>nul Dir "%BoxData%" /B /S /A:D`) DO Call :MyDel "%%d"
Pause
GoTo :Eof

:Count
Set /A N+=1
Set "@@%N%=%~1"
GoTo :Eof

:MyDel
FOR /F "usebackq tokens=1* delims==" %%f IN (`Set "@@"`) DO If Exist "%~1\%%~g" (
Attrib -R -H -S "%~1\%%~g"
Del "%~1\%%~g"
)
GoTo :Eof

Iska
05-01-2019, 15:50
OS WinXP SP3, выше PoSh v 2.0, увы не прыгнуть... »
Угу. Там по-старому, через фильтр — Where-Object -FilterScript { -not $_.PSIsContainer }.

dassen
05-01-2019, 19:55
megaloman, большое спасибо. То, что надо. Основную задачу батник выполняет.
CMD тоже можно »
именно cmd и интересовало.

Iska
09-01-2019, 06:03
передать весь список искомых файлов через Include в Get-ChildItem - интересная идея »
С тех пор, как Microsoft начал указывать типы параметров у командлетов — жить стало легче, жить стало веселей ;).

если вы раскрашиваете сообщения исходя из их разной ценности »
Нет, не поэтому. Просто группировка вывода, цветовая дифференциация штанов.

используете стандартные Write-Debug, Write-Verbose, Write-Info - они и сами раскрасят, и ими можно извне хоть как-то управлять »
Если бы это были Debug/Verbose/Info сообщения — тогда, да. В данном случае я не вижу нужды наделять простой вывод искусственным смыслом. Я понимаю Вашу мысль, но я вижу ровно два места вывода — stdout и stderr, и не стремлюсь здесь что-то менять. И, к тому же, мне нужно, чтобы пользователь, например, гарантированно видел сообщение о той или иной ошибке.

но вообще, это бесполезное самолюбование - как в кино: по экрану бежит куча текста который никто не читает и в принципе не в состоянии прочитать и проанализировать. »
У меня — не бежит. У меня — при нужде передаётся в редактор Far Manager'а:
edit:< powershell.exe -File "C:\Мои проекты\0235\0003.ps1"
Зачем тогда пользовать консоль, если не пользовать все её возможности?!

Лучше бы уж тогда Write-Progress впилили »
Для удаления нескольких сотен файлов? Не вижу особого смысла. Основной временно́́й расход здесь займёт поиск файлов — FindFirst()/FindNext(), а само удаление будет тупо в уже заполненный кэш писаться.

заворачивать всё в глобальные if - ну так себе подход неудобно отслеживать к чему относится закрывающая скобка и else - разверните условие и сделайте выход сразу после if »
Редактор вменяемый фолдинг не поддерживает, что ли? Я вот как раз наоборот, терпеть не могу кучу этих вечных выходов посерёд кода. Как по мне — так в моём подходе зараз виден весь алгоритм целиком и полностью. Впрочем, это кому как, соглашусь, что зависит сие от восприятия конкретного человека.

.Net библиотеки не знают ничего про PSdisk, поэтому ваши скритпы невозможно тестировать стандартным Pester
метод файлового объекта Delete() вместо Remove-Item - тоже та ещё засада - я не могу в начале скрипта к примеру написать $PSDefaultParameterValues.Add("Remove-Item:WhatIf",$True) и посмотреть: что же происходит »
Вы не поверите: чем теснее мне приходится общаться с командлетами, тем больше мне начинает нравиться прямое использование методов .Net — меньше шансов нарваться на какой-нибудь очередной затык в реализации командлета :).




© OSzone.net 2001-2012