Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Скриптовые языки администрирования Windows (http://forum.oszone.net/forumdisplay.php?f=102)
-   -   [решено] Поиск в csv файле (http://forum.oszone.net/showthread.php?t=343397)

ejik_off 23-12-2019 17:12 2901799

Поиск в csv файле
 
Здравствуйте, гуру PS!!!
Есть файл тхт в нем содержатся логины:
ppetrov
iivanov
ssidorov
...
и есть csv файл в формате samaccountname,count
samaccountname,count
ppetrov,1
iivanov,1
ssidorov,2
нужно сделать поиск, т.е логины из тхт файла сравнить с логинами из csv-файла если логин найден, то поле count увеличить на 1, если не найдено то добавить в конец файла в поле samaccountname: логин и в count: 1
Код:

$txt = get-content c:\tmp\usr.txt
$csv = import-csv c:\tmp\usr_list.csv -Delimiter ","


foreach($user_txt in $txt) {
    foreach($user_csv in $csv){
        if($user_txt -eq $user_csv.samaccountname) {
            как изменить колонку count?
        }
        else {$user_txt,1 | out-file c:\tmp\usr_list.csv -Append - тоже не знаю как правильно вставить}
    }
}


Iska 23-12-2019 19:01 2901817

ejik_off, вот взяли бы, да приложили в архиве и тот, и другой файл для облегчения работы отвечающим.

Попробуйте так:
Скрытый текст
Код:

$sTxtFile    = 'C:\Мои проекты\0289\0001.txt'
$sCSVFile    = 'C:\Мои проекты\0289\0002.csv'

$sTxtContent = Get-Content -Path $sTxtFile
$sCSVContent = Import-Csv  -Path $sCSVFile

$sTxtContent | ForEach-Object -Process {
    $oCSVObject = $sCSVContent | Where-Object -Property 'samaccountname' -eq -Value $_
        if($oCSVObject) {
            $oCSVObject.count = [System.String]([System.Int32]($oCSVObject.count) + 1)
        } else {
            $sCSVContent += [PSCustomObject]@{samaccountname = $_; count = '1'}
        }
}

$sCSVContent | ConvertTo-Csv -NoTypeInformation | ForEach-Object -Process {
    $_.Replace('"','')
} | Set-Content -Path $sCSVFile -Force


ejik_off 23-12-2019 20:38 2901836

Цитата:

Цитата Iska
ejik_off, вот взяли бы, да приложили в архиве и тот, и другой файл для облегчения работы отвечающим. »

Прошу прощения, не подумал даже о прикрепе фалов. :sorry:
Огромное спасибо за скрипт, работает!!!! :up

greg zakharov 23-12-2019 21:27 2901847

Iska, венгерская нотация в PowerShell? Переутомление? Да и лучше сделать так (PowerShell v6):
Код:

$csv, $txt = (Import-Csv .\input.csv -Delimiter ','), (Get-Content .\input.txt)
$txt.ForEach{
  .({ $csv += [PSCustomObject]@{samaccountname = $_; count = 1} },{
    ++[Int32]$csv[$csv.samaccountname.IndexOf($_)].count
  })[[Byte]($_ -in $csv.samaccountname)]
}
($csv | ConvertTo-Csv) -replace '"' | Out-File .\input.csv

Результат теста производительности:
Код:

time {
  $csv, $txt = (Import-Csv .\input.csv -Delimiter ','), (Get-Content .\input.txt)
  $txt.ForEach{
    .({ $csv += [PSCustomObject]@{samaccountname = $_; count = 1} },{
      ++[Int32]$csv[$csv.samaccountname.IndexOf($_)].count
    })[[Byte]($_ -in $csv.samaccountname)]
  }
  ($csv | ConvertTo-Csv) -replace '"' | Out-File .\input.csv
}, {
  $sTxtFile    = '.\input1.txt'
  $sCSVFile    = '.\input1.csv'

  $sTxtContent = Get-Content -Path $sTxtFile
  $sCSVContent = Import-Csv  -Path $sCSVFile

  $sTxtContent | ForEach-Object -Process {
      $oCSVObject = $sCSVContent | Where-Object -Property 'samaccountname' -eq -Value $_
          if($oCSVObject) {
              $oCSVObject.count = [System.String]([System.Int32]($oCSVObject.count) + 1)
          } else {
              $sCSVContent += [PSCustomObject]@{samaccountname = $_; count = '1'}
          }
  }

  $sCSVContent | ConvertTo-Csv -NoTypeInformation | ForEach-Object -Process {
      $_.Replace('"','')
  } | Set-Content -Path $sCSVFile -Force
}

# итог:
Total ms: 37.7992
Total ms: 108.8279

Как говорится, почувствуйте разницу.

ejik_off 24-12-2019 05:43 2901895

greg zakharov, классно, осталось понять как он работает )))

ejik_off 24-12-2019 07:53 2901906

на рабочем компе скрипт не работает, видно версии PS разные. На раб.станции версия 5.1.17763.771
Скрытый текст

Сбой вызова метода из-за отсутствия в [System.Management.Automation.PSObject] метода с именем "op_Addition".

строка:12 знак:8

+ $sCSVContent += [PSCustomObject]@{samaccountname = $_; count = ...

+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+ CategoryInfo : InvalidOperation: (op_Addition:String) [], RuntimeException

+ FullyQualifiedErrorId : MethodNotFound

как адаптировать скрипт?

DJ Mogarych 24-12-2019 08:55 2901913

ejik_off, используйте первый вариант. Вряд ли в данном случае разница в 70 миллисекунд имеет большое значение.

ejik_off 24-12-2019 09:11 2901914

оба варианта дают такую ошибку

DJ Mogarych 24-12-2019 09:36 2901919

ejik_off, дайте примеры файлов, хоть будет на чём протестировать.

ejik_off 24-12-2019 10:13 2901923

прикрепил архив

DJ Mogarych 24-12-2019 11:15 2901929

Код:

$txt = gc D:\temp\test\Users.txt
[array]$csv = import-csv D:\temp\test\user_list.csv

foreach ($login in $txt) {
    if ($login -notin $csv.samaccountname) {
    $csv += [pscustomobject]@{samaccountname="$login";count="1"}
    }
    else {([double]($csv |? samaccountname -eq "$login").count)++}
}

$csv |export-csv D:\temp\test\user_list.csv -NoTypeInformation


ejik_off 24-12-2019 12:21 2901935

DJ Mogarych, спасибо, работает!

Iska 24-12-2019 19:22 2901979

ejik_off, это потому, что у Вас в примере в csv-файле одна строка. Я всё время забываю, что нужно постоянно отслеживать эти долбаные просчёты в архитектуре милые шалости PowerShell'a.

Замените в том коде эту строку:
Код:

$sCSVContent = Import-Csv  -Path $sCSVFile
на эту:
Код:

$sCSVContent = , (Import-Csv  -Path $sCSVFile)

DJ Mogarych 25-12-2019 08:48 2902050

А, так вот в чём дело - а я и думаю, почему в csv просто так нельзя было добавить строку, и надо было принудительно указывать, что это массив, а не кастом-объект. В принципе, логично - PS что видит, так и интерпретирует, объект один, так почему это должно быть массивом?

greg zakharov 25-12-2019 10:38 2902073

Какие все однако переутомившиеся: сперва венгерская нотация, потом бредни про массив...
Код:

$c = Import-Csv .\input.csv
$c.GetType() # возвращает Object[]


Iska 25-12-2019 20:22 2902186

Цитата:

Цитата DJ Mogarych
В принципе, логично - PS что видит, так и интерпретирует, объект один, так почему это должно быть массивом? »

Я бы предпочёл, чтобы это был массив из одного элемента — вот это было бы вполне логично. А когда тип возвращаемого командлетом значения зависит от количества данных — это, простите, совсем нелогично. И по факту на каждый такой случай всё равно приходится при кодировании либо «лепить» подобную конструкцию, либо отдельно учитывать случай с возвращаемым базовым типом вместо массива.

Ладно, я понимаю, когда совсем нет элементов — тут деваться некуда. Это надо проверять. Так было с незапамятных времён, так и осталось. Но PowerShell теперь к этим двум вариантам добавляет ещё и третий вариант, абсолютно бессмысленный с точки зрения программирования, но который тоже приходится учитывать.

Может быть, в шестой версии, которая у коллеги greg zakharov, это уже не так, и для одной строки командлет Import-Csv возвращает именно массив из одного элемента. Как и прочие командлеты в аналогичных случаях. Дай-то бог. Но у меня, в 5.1, пока что так:
Скрытый текст

greg zakharov 25-12-2019 20:46 2902194

Iska, специально для вас:
Код:

E:\sandbox
λ $PSVersionTable.PSVersion

Major  Minor  Build  Revision
-----  -----  -----  --------
5      1      18362  145


E:\sandbox
λ $c = Import-Csv .\input.txt

E:\sandbox
λ $c.GetType()

IsPublic IsSerial Name                                    BaseType
-------- -------- ----                                    --------
True    True    Object[]                                System.Array



E:\sandbox
λ $c[0]

samaccountname count
-------------- -----
ppetrov        1

E:\sandbox
λ $c[0].samaccountname
ppetrov

Тот же результат будет и в шестерке и в семерке.

Petya V4sechkin 25-12-2019 21:58 2902214

Цитата:

Цитата greg zakharov
И да, вы непременно удалите это сообщение, сославшись на якобы нарушение форумных правил.

Я удалю ваши сообщения, поскольку они явным образом нарушают пункты 3.1 и 3.7 общих правил форума.

YuS_2 26-12-2019 07:34 2902286

Цитата:

Цитата Iska
Я бы предпочёл, чтобы это был массив из одного элемента — вот это было бы вполне логично. »

А если потребуется не массив, а единственный элемент, сохраняемый с определенным типом? Ситуации бывают разные, иногда, как раз, требуется ограничить данные, чтобы получался на выходе не массив.

Цитата:

Цитата Iska
А когда тип возвращаемого командлетом значения зависит от количества данных — это, простите, совсем нелогично. »

При наличии функциональности автоматического приведения типов, это, скорее, логично. И не в командлете загвоздка, кстати...

Цитата:

Цитата Iska
И по факту на каждый такой случай всё равно приходится при кодировании либо «лепить» подобную конструкцию, либо отдельно учитывать случай с возвращаемым базовым типом вместо массива. »

Всё гораздо проще:
Если требуется таки массив, при любом количестве данных, то необходимо указать тип переменной, либо:


Цитата:

Цитата Iska
для одной строки командлет Import-Csv возвращает именно массив из одного элемента. Как и прочие командлеты в аналогичных случаях. »

Командлет, в данном случае, не при чем, так работало:


и продолжает работать автоматическое приведение типов:


И кроме того, есть ведь специальный оператор массива:
The array operator is useful in scripts when you are getting objects, but do not know how many objects you get.
Код:

$p = @(Get-Process Notepad)
Так что логика, определенно, присутствует... к ней просто надо привыкнуть.

Busla 26-12-2019 10:53 2902307

Цитата:

Цитата Iska
Я бы предпочёл, чтобы это был массив из одного элемента — вот это было бы вполне логично. А когда тип возвращаемого командлетом значения зависит от количества данных — это, простите, совсем нелогично. И по факту на каждый такой случай всё равно приходится при кодировании либо «лепить» подобную конструкцию, либо отдельно учитывать случай с возвращаемым базовым типом вместо массива. »

Тип не зависит от количества. Практически все командлеты написаны под функциональный стиль использования - они не "возвращают", они выдают результат в первый поток. Это вы своим любимым императивным подходом обращаетесь к неявным преобразованиям типов.

JimmLight 15-04-2021 12:31 2955766

А можно ли как-то реализовать поиск в csv следующим образом: если значение "Слесарь-монтажник" имеется в csv, то копируем всю строку с этим значением в новый csv файл.

JimmLight 16-04-2021 06:20 2955813

Цитата:

Цитата JimmLight
А можно ли как-то реализовать поиск в csv следующим образом: если значение "Слесарь-монтажник" имеется в csv, то копируем всю строку с этим значением в новый csv файл. »

Попробовал таким образом:
Код:

$Files = "C:\исходный файл.csv"
Get-Content $Files | Select-String "значение поиска" | Export-Csv "C:\Конечный файл.csv" -Encoding UTF8 -Delimiter ";"

Добавляется много непонятных значений столбцов:
Код:

"IgnoreCase";"LineNumber";"Line";"Filename";"Path";"Pattern";"Context";"Matches"

DJ Mogarych 16-04-2021 09:03 2955815

JimmLight, CSV - это структурированный файл, и работать с ним как с обычным текстовым неверно.
Как называется колонка, в которой находится "слесарь-монтажник"?

JimmLight 16-04-2021 09:55 2955818

Цитата:

Цитата DJ Mogarych
JimmLight, CSV - это структурированный файл, и работать с ним как с обычным текстовым неверно.
Как называется колонка, в которой находится "слесарь-монтажник"? »

"слесарь монтажник" может быть в нескольких колонках: или "Колонка1" или "Колонка2" или "Колонка4" или "Колонка6".

DJ Mogarych 16-04-2021 10:04 2955821

Код:

(Import-Csv "C:\исходный файл.csv") -match "слесарь-монтажник"
В зависимости от разделителя, может понадобиться добавить опцию -Delimiter

JimmLight 16-04-2021 10:23 2955822

Цитата:

Цитата DJ Mogarych
В зависимости от разделителя, может понадобиться добавить опцию -Delimiter »

Код:

(Import-Csv "C:\исходный файл.csv" -Encoding UTF8 -Delimiter ";") -match "слесарь-монтажник" | Export-Csv "C:\конечный файл.csv" -Encoding UTF8 -Delimiter ";"
Если я правильно понимаю, то должно быть так?
Почему то пустой "C:\конечный файл.csv" создаётся.

DJ Mogarych 16-04-2021 10:24 2955823

Вы сначала без экспорта отладьте, чтобы нормально запускалось и выводило нужное.
Рекомендую Powershell ISE.

Foreigner 16-04-2021 16:28 2955851

Цитата:

Цитата JimmLight
Почему то пустой "C:\конечный файл.csv" создаётся. »

Код:

Import-Csv .\1.csv -Delimiter ";" |
Foreach-Object {                 
                                                         
    if ($_.psobject.properties.value -eq 'слесарь-механик')
    {  Export-Csv -InputObject $_ 2.csv -Append; continue }                                                     
}

Encoding добавите, если необходимо.


Время: 00:03.

Время: 00:03.
© OSzone.net 2001-