Проходить по файлам в каталоге с помощью 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

Ответы:


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
}

Это создает один выходной файл с именем "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 в системный путь.


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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.