Подтвердить что ты не робот

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

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

Я все еще очень новичок в PowerShell, поэтому не уверен, что искать и как подойти к этому. Моя текущая концепция с использованием псевдокода:

set-content file (get-content unless line contains amount)

Однако я не могу понять, как сделать что-то вроде содержащего.

4b9b3361

Ответ 1

Это не самый эффективный в мире, но это должно работать:

get-content $file |
    select -Skip 1 |
    set-content "$file-temp"
move "$file-temp" $file -Force

Ответ 2

В то время как я действительно восхищаюсь ответом от @hoge как для очень краткой техники, так и для функции обертки, чтобы обобщить ее, и я поощряю ее, я вынужден прокомментировать два других ответа, которые используют временные файлы (он грызет мне, как ногти на доске!).

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

(Get-Content $file | Select-Object -Skip 1) | Set-Content $file

... или в краткой форме:

(gc $file | select -Skip 1) | sc $file

Ответ 3

Используя нотацию переменных, вы можете сделать это без временного файла:

${C:\file.txt} = ${C:\file.txt} | select -skip 1

function Remove-Topline ( [string[]]$path, [int]$skip=1 ) {
  if ( -not (Test-Path $path -PathType Leaf) ) {
    throw "invalid filename"
  }

  ls $path |
    % { iex "`${$($_.fullname)} = `${$($_.fullname)} | select -skip $skip" }
}

Ответ 4

Мне просто нужно было выполнить одну и ту же задачу, а gc | select ... | sc заняла 4-х гигабайт ОЗУ на моей машине, читая файл размером 1,6 фунта. Он не завершился в течение как минимум 20 минут после прочтения всего файла (как сообщается Read Bytes в Process Explorer), при котором Я должен был убить его.

Моим решением было использование более .NET-подхода: StreamReader + StreamWriter. См. Этот ответ для отличного ответа на обсуждение perf: В Powershell наиболее эффективный способ разделить большой текстовый файл по типу записи?

Ниже мое решение. Да, он использует временный файл, но в моем случае это не имело значения (это было огромное создание таблицы SQL и вставка файла инструкций):

PS> (measure-command{
    $i = 0
    $ins = New-Object System.IO.StreamReader "in/file/pa.th"
    $outs = New-Object System.IO.StreamWriter "out/file/pa.th"
    while( !$ins.EndOfStream ) {
        $line = $ins.ReadLine();
        if( $i -ne 0 ) {
            $outs.WriteLine($line);
        }
        $i = $i+1;
    }
    $outs.Close();
    $ins.Close();
}).TotalSeconds

Он вернул:

188.1224443

Ответ 5

Вдохновленный ответом AASoft, я вышел, чтобы улучшить его немного больше:

  • Избегайте переменной цикла $i и сравнения с 0 в каждом цикле
  • Оберните выполнение в блок try..finally, чтобы всегда закрывать используемые файлы
  • Сделайте решение для произвольного количества строк для удаления с начала файла
  • Используйте переменную $p для ссылки на текущий каталог

Эти изменения приводят к следующему коду:

$p = (Get-Location).Path

(Measure-Command {
    # Number of lines to skip
    $skip = 1
    $ins = New-Object System.IO.StreamReader ($p + "\test.log")
    $outs = New-Object System.IO.StreamWriter ($p + "\test-1.log")
    try {
        # Skip the first N lines, but allow for fewer than N, as well
        for( $s = 1; $s -le $skip -and !$ins.EndOfStream; $s++ ) {
            $ins.ReadLine()
        }
        while( !$ins.EndOfStream ) {
            $outs.WriteLine( $ins.ReadLine() )
        }
    }
    finally {
        $outs.Close()
        $ins.Close()
    }
}).TotalSeconds

Первое изменение привело к тому, что время обработки моего 60-мегабайтного файла сократилось с 5.3s до 4s. Остальные изменения более косметичны.

Ответ 6

Я только что узнал на веб-сайте:

Get-ChildItem *.txt | ForEach-Object { (get-Content $_) | Where-Object {(1) -notcontains $_.ReadCount } | Set-Content -path $_ }

Или вы можете использовать псевдонимы, чтобы сделать его коротким, например:

gci *.txt | % { (gc $_) | ? { (1) -notcontains $_.ReadCount } | sc -path $_ }

Ответ 7

$x = get-content $file
$x[1..$x.count] | set-content $file

Просто так много. Далее следует длинное скучное объяснение. Get-content возвращает массив. Мы можем "индексировать" в переменные массива, как показано в this и other Сообщения сценариев Guys.

Например, если мы определим такую ​​переменную массива,

$array = @("first item","second item","third item")

поэтому $array возвращает

first item
second item
third item

то мы можем "индексировать" этот массив для извлечения только его 1-го элемента

$array[0]

или только его второй

$array[1]

или диапазон значений индекса со второго по последний.

$array[1..$array.count]

Ответ 8

skip` не работает, поэтому мой способ обхода

$LinesCount = $(get-content $file).Count
get-content $file |
    select -Last $($LinesCount-1) | 
    set-content "$file-temp"
move "$file-temp" $file -Force

Ответ 9

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

 $firstLine, $restOfDocument = Get-Content -Path $filename 
 $modifiedContent = $restOfDocument 
 $modifiedContent | Out-String | Set-Content $filename

Ответ 10

Для небольших файлов вы можете использовать это:

& C:\windows\system32\more +1 oldfile.csv > newfile.csv | из-нуль

... но это не очень эффективно при обработке моего файла примера 16 МБ. Кажется, что он не завершает и не освобождает блокировку newfile.csv.