Могу ли я оптимизировать этот анализатор PowerShell - PullRequest
0 голосов
/ 21 февраля 2019

Я написал сценарий PowerShell для чтения файлов с разделителями и обхода их построчно.Этот сценарий сохраняет значения атрибутов в переменных и записывает эти значения в файл, когда встречается конец строки.

Есть ли способ оптимизировать этот сценарий для большей скорости, если у меня не установлена ​​платформа .Net?

rm storage.txt
$job_counter = 0;
$att_counter = 0;

foreach ($line in Get-Content .\a.txt) {
    if ($line -match '^end$') {
        $job_counter++;
    }
}

echo "File has $job_counter jobs"

$job_counter = 0;

foreach ($line in Get-Content .\a.txt) {
    if ($line -notmatch '^end$') {
        $line_header = ($line.Split(":")[0])
        $line_value = ($line.Split(":")[1])
        switch ($line_header) {
            insert_job      {$insert_job      = $line_value.trim();break}
            job_type        {$job_type        = $line_value.trim();break}
            command         {$command         = $line_value.trim();break}
            machine         {$machine         = $line_value.trim();break}
            owner           {$owner           = $line_value.trim();break}
            permission      {$permission      = $line_value.trim();break}
            date_conditions {$date_conditions = $line_value.trim();break}
            days_of_week    {$days_of_week    = $line_value.trim();break}
            start_times     {$start_times     = $line_value.trim();break}
            description     {$description     = $line_value.trim();break}
            std_out_file    {$std_out_file    = $line_value.trim();break}
            std_err_file    {$std_err_file    = $line_value.trim();break}
            alarm_if_fail   {$alarm_if_fail   = $line_value.trim();break}
            end             {$end             = $line_value.trim();break}
            box_name        {$box_name        = $line_value.trim();break}
            condition       {$condition       = $line_value.trim();break}
            run_window      {$run_window      = $line_value.trim();break}
            n_retrys        {$n_retrys        = $line_value.trim();break}
            term_run_time   {$term_run_time   = $line_value.trim();break}
            box_terminator  {$box_terminator  = $line_value.trim();break}
            job_terminator  {$job_terminator  = $line_value.trim();break}
            min_run_alarm   {$min_run_alarm   = $line_value.trim();break}
            max_run_alarm   {$max_run_alarm   = $line_value.trim();break}
            profile         {$profile_name    = $line_value.trim();break}
        }
        $att_counter++;
    } else {
        $job_counter++
        echo "encountered job number $job_counter, it has $att_counter attributes"
        echo "'$insert_job','$job_type','$command','$machine','$owner','$permission','$date_conditions','$days_of_week','$start_times','$description','$std_out_file','$std_err_file','$alarm_if_fail','$end','$box_name','$condition','$run_window','$n_retrys','$term_run_time','$box_terminator','$job_terminator','$min_run_alarm','$max_run_alarm','$profile_name'" >>storage.txt

        Clear-Variable -Name "insert_job";
        Clear-Variable -Name "job_type";
        Clear-Variable -Name "command";
        Clear-Variable -Name "machine";
        Clear-Variable -Name "owner";
        Clear-Variable -Name "permission";
        Clear-Variable -Name "date_conditions";
        Clear-Variable -Name "days_of_week";
        Clear-Variable -Name "start_times";
        Clear-Variable -Name "description";
        Clear-Variable -Name "std_out_file";
        Clear-Variable -Name "std_err_file";
        Clear-Variable -Name "alarm_if_fail";
        Clear-Variable -Name "end";
        Clear-Variable -Name "box_name";
        Clear-Variable -Name "condition";
        Clear-Variable -Name "run_window";
        Clear-Variable -Name "n_retrys";
        Clear-Variable -Name "term_run_time";
        Clear-Variable -Name "box_terminator";
        Clear-Variable -Name "job_terminator";
        Clear-Variable -Name "min_run_alarm";
        Clear-Variable -Name "max_run_alarm";
        Clear-Variable -Name "profile_name";

        $att_counter = 0;
    }
}

Ответы [ 2 ]

0 голосов
/ 22 февраля 2019

В комментариях и в * 1001 есть хорошие указатели * в ответе ТесселлингаГеклера , но позвольте мне попытаться собрать все это вместе с дополнительными улучшениями скорости - см. Комментарии в коде.

rm storage.txt
$job_counter = 0
$att_counter = 0

# Read all lines into memory up front, using the .NET framework directly
# which is much faster than using Get-Content.    
$allLines = [IO.File]::ReadAllLines("$PWD/a.txt")

# Count the lines that contain 'end' exactly to determine
# the number of jobs.
$job_counter = ($allLines -eq 'end').Count

"File has $job_counter jobs"

$job_counter = 0

# Initialize the hashtable whose entries will contain the values
# (rather than individual variables).
$values = [ordered] @{}

# Use a `switch` statement to process the lines, which is generally
# faster than a `foreach` loop.
switch ($allLines) {
  'end' {  # Use string equality (not regex matching), which is faster.
    $job_counter++
    "encountered job number $job_counter, it has $att_counter attributes"
    # Write the values to 
    "'$($values.insert_job)','$($values.job_type)','$($values.command)','$($values.machine)','$($values.owner)','$($values.permission)','$($values.date_conditions)','$($values.days_of_week)','$($values.start_times)','$($values.description)','$($values.std_out_file)','$($values.std_err_file)','$($values.alarm_if_fail)','$($values.end)','$($values.box_name)','$($values.condition)','$($values.run_window)','$($values.n_retrys)','$($values.term_run_time)','$($values.box_terminator)','$($values.job_terminator)','$($values.min_run_alarm)','$($values.max_run_alarm)','$($values.profile)'" >>storage.txt
    # Clear the values from the hashtable.
    $values.Clear()
  }
  default { 
    # Split the line at hand into field name and value...
    $fieldName, $value = $_ -split ':', 2, 'SimpleMatch'
    # ... and add an entry for the pair to the hashtable.
    $values.$fieldName = $value.trim()
    $att_counter++
  }
}

Примечание. Приведенное выше решение не проверяет имена полей, найденные во входном файле;для этого потребуется дополнительная работа.

0 голосов
/ 22 февраля 2019

Get-Content .\a.txt медленный, замените его на [system.io.file]::ReadAllLines('c:\full\path\to\file\a.txt'), что намного быстрее.

Избавьтесь от всего первого цикла и не отражайте количество заданий вообще.Если вам нужно сделать это, протолкните цикл вниз по стеку и используйте $jobCount = ($LinesLoadedOnce -match '^end$').Count и используйте -match для выполнения цикла / фильтрации вместо foreach.

вместо вызова Clear-Variable много раз в строкетекстового файла и многократного запуска командлета, вызовите его один раз и передайте для очистки массив имен, например Clear-Variable -Name "insert_job", "job_type", "command", ...

Вместо использования >>storage.txt, который открывает и закрывает текстфайл один раз в строку, собрать вывод в массив и записать его один раз в файл с set-content

$results = foreach ($line in [system.io.file]::ReadAllLines('c:\full\path\to\file\a.txt'))
{
    #code here

    "'$insert_job','$job_type','$command', .."

}

$results | Set-Content -Path storage.txt

Остальное становится более зависимым от формата вашего файла, насколько он велик, еслиесть строки, которые вы пропускаете, но это может стать чем-то вроде:

$headers = @(
    'insert_job'
    'job_type'
    'command'
    'machine'
    'owner'
    'permission'
    'date_conditions'
    'days_of_week'
    'start_times'
    'description'
    'std_out_file'
    'std_err_file'
    'alarm_if_fail'
    'end'
    'box_name'
    'condition'
    'run_window'
    'n_retrys'
    'term_run_time'
    'box_terminator'
    'job_terminator'
    'min_run_alarm'
    'max_run_alarm'
    'profile'
)

$headerRegex = "^($($headers -join '|'))\s*:\s*(.*?)\s*$"

$data = [ordered]@{}
foreach($h in $headers) { $data[$h] = $null }

$results = foreach ($line in [system.io.file]::ReadAllLines('c:\full\path\to\file\a.txt')) {

    if ($line -match $headerRegex) {
        $data[$matches[1]] = $matches[2]
    }
    elseif ($line -eq 'end') {
        [PSCustomObject]$data
        $data = [ordered]@{}
        foreach($h in $headers) { $data[$h] = $null }
    }
}

$results | Export-Csv storage.txt -NoTypeInformation

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

Я не проверял его, потому что не знаю содержимого вашего файла.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...