Проходить по файлам в каталоге с помощью PowerShell

243

Как я могу изменить следующий код для просмотра всех файлов .log в каталоге, а не только одного файла?

Мне нужно перебрать все файлы и удалить все строки, которые не содержат «step4» или «step9». В настоящее время это создаст новый файл, но я не уверен, как использовать for eachцикл здесь (новичок).

Фактические файлы названы так: 2013 09 03 00_01_29.log . Я хотел бы, чтобы выходные файлы либо перезаписывали их, либо имели одинаковое имя с добавлением «out».

$In = "C:\Users\gerhardl\Documents\My Received Files\Test_In.log"
$Out = "C:\Users\gerhardl\Documents\My Received Files\Test_Out.log"
$Files = "C:\Users\gerhardl\Documents\My Received Files\"

Get-Content $In | Where-Object {$_ -match 'step4' -or $_ -match 'step9'} | `
Set-Content $Out
user2725402
источник

Ответы:

363

Попробуйте это:

Get-ChildItem "C:\Users\gerhardl\Documents\My Received Files" -Filter *.log | 
Foreach-Object {
    $content = Get-Content $_.FullName

    #filter and save content to the original file
    $content | Where-Object {$_ -match 'step[49]'} | Set-Content $_.FullName

    #filter and save content to a new file 
    $content | Where-Object {$_ -match 'step[49]'} | Set-Content ($_.BaseName + '_out.log')
}
Шей Леви
источник
Спасибо. Часть BaseName не работает (версия 1) - но мне удалось сначала создать резервную копию полного файла, а затем внести изменения в исходный файл.
user2725402
6
Для v1 вы можете использовать следующее для извлечения базового имени: [io.path] :: GetFileNameWithoutExtension ($ name)
Шей Леви
Если я заменю BaseNameс FullNameя получаю то , что хочу.
М--
78

Для получения содержимого каталога вы можете использовать

$files = Get-ChildItem "C:\Users\gerhardl\Documents\My Received Files\"

Затем вы можете перебрать и эту переменную:

for ($i=0; $i -lt $files.Count; $i++) {
    $outfile = $files[$i].FullName + "out" 
    Get-Content $files[$i].FullName | Where-Object { ($_ -match 'step4' -or $_ -match 'step9') } | Set-Content $outfile
}

Еще более простой способ сделать это - foreachцикл (благодаря @Soapy и @MarkSchultheiss):

foreach ($f in $files){
    $outfile = $f.FullName + "out" 
    Get-Content $f.FullName | Where-Object { ($_ -match 'step4' -or $_ -match 'step9') } | Set-Content $outfile
}
PVitt
источник
Это создает один выходной файл с именем "out.log". Как я могу создать отдельный выходной файл для каждого входного файла?
user2725402
@ user2725402 Я добавил входной зависимый выходной файл с именем <input file name> out
PVitt
не уверен, что я делаю неправильно, но это не работает - теперь я не получаю выходные файлы (и без ошибок): $files = Get-ChildItem "C:\Users\gerhardl\Documents\My Received Files\" $files | Where-Object { $outFile = $_.Name + "out" Get-Content $_.FullName | Where-Object { $_ -match 'step4' -or $_ -match 'step9' } | Set-Content $outFile }
user2725402
2
Вы также можете сделать foreach ($f in Get-ChildItem "C:\Users\gerhardl\Documents\My Received Files\") { ... }
Soapy
1
или используйтеForEach ($f in $files){...}
Mark Schultheiss
31

Если вам необходимо выполнить рекурсивный цикл внутри каталога для определенного типа файла, используйте команду ниже, которая фильтрует все файлы типа docфайла

$fileNames = Get-ChildItem -Path $scriptPath -Recurse -Include *.doc

Если вам нужно выполнить фильтрацию для нескольких типов, используйте команду ниже.

$fileNames = Get-ChildItem -Path $scriptPath -Recurse -Include *.doc,*.pdf

Сейчас $fileNames переменная действует как массив, из которого вы можете зациклить и применить свою бизнес-логику.

Сарат Аванаву
источник
Что меня беспокоило, так это отсутствие скрытых и / или системных файлов. Чтобы увидеть их, вы должны использовать -Forceпараметр Get-ChildItem. См. Его документ в docs.microsoft.com/en-us/powershell/module/… .
til_b
-6

Другие ответы хороши, я просто хочу добавить ... другой подход, используемый в PowerShell: установите утилиты GNUWin32 и используйте grep для просмотра строк / перенаправления вывода в файл http://gnuwin32.sourceforge.net/

Это перезаписывает новый файл каждый раз:

grep "step[49]" logIn.log > logOut.log 

Это добавляет вывод журнала в случае, если вы перезаписываете файл входа в систему и хотите сохранить данные:

grep "step[49]" logIn.log >> logOut.log 

Примечание: чтобы иметь возможность использовать утилиты GNUWin32 глобально, вы должны добавить папку bin в системный путь.

user1628658
источник
18
Этот вопрос был помечен как PowerShell, а не Unix
SteveC
2
Да. Очевидно. Мое мнение было довольно простым: вы можете использовать утилиты GNUWin32 в Windows, поэтому вы можете легко использовать инструменты * nix в Powershell. Работает. Никто никогда не говорил, что ответ должен быть полностью родным для Powershell. И даже если они это сделали, вы все равно можете вызывать Win32 Utils напрямую из Powershell. AFAIK, используя то, что доступно и совместимо, на самом деле не плохо.
user1628658
2
Я бы отредактировал свой предыдущий комментарий, но я преодолел 5-минутный лимит: SteveC: Вы говорите, что включение инструментов GNU, которые отлично работают под Windows, как-то бросает вызов Powershell? Это одна вещь. Я понимаю, что разработка этого чисто в Powershell может быть более продуктивной в краткосрочной перспективе. В долгосрочной перспективе расширение возможностей имеет больше преимуществ. Вы добавляете больше опций и работаете полностью в Windows и Powershell без каких-либо эмуляторов Linux, таких как Cygwin. Поэтому, пока я понимаю вашу оговорку, я не согласен.
user1628658
5
Речь шла о поиске в PowerShell, а не о множестве других языков, которые можно было бы использовать.
SteveC
1
Ответы должны быть на вопрос. Этот вопрос был явным в том смысле, что он хотел получить ответ в PowerShell. Ваш ответ был установить что-то и использовать его. Вы могли бы предложить установить Ruby и т. Д.
SteveC