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

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

m0nkrus 30-04-2021 21:26 2956796

Удалить первый байт в файле
 
Приветствую!

Задача следующая: нужно удалить первый байт в файле. Этот процесс нужно автоматизировать, поскольку этот байт мне нужно удалить более чем в сотне файлов. Так что если на выходе получится скрипт, который опрашивает директорию с субдиректориями, и все находящиеся в них файлы смещает на один байт вверх, уничтожая этот байт, было бы идеально. Если имена конечных файлов слегка изменятся (например, к имени прибавится цифра 1), это не принципиально.

Foreigner 30-04-2021 21:43 2956797

Как-то так (pwsh.exe)
Код:

foreach ($file in (Get-Childitem -File -Recurse))
{
    (Get-Content $file -AsByteStream -Raw)[1..($file.length-1)] | Set-Content $file -AsByteStream
}


m0nkrus 30-04-2021 22:38 2956803

Foreigner, я совсем не рублю в PowerShell. Попробовал создать скрипт *.ps1, куда записал эти строки. Поместил скрипт в папку с файлами и запустил. Скрипт выдал ошибку и закрылся.
Что я сделал не так?

DJ Mogarych 30-04-2021 22:45 2956804

Цитата:

Цитата m0nkrus
ошибку »

Какую?

Вставьте в начало скрипта

Код:

cd "путь к нужной папке"
и скрипт в папку не помещайте, он же у себя тоже будет пытаться байт откусить.

Foreigner 01-05-2021 00:01 2956809

Цитата:

Цитата m0nkrus
Любой язык »

Цитата:

Цитата m0nkrus
Что я сдела не так? »

Тогда попробуйте в таком виде (для powershell.exe)
Код:

foreach ($file in (Get-Childitem -File -Recurse))
{
    (Get-Content $file -Encoding byte -Raw)[1..($file.length-1)] | Set-Content $file -Encoding byte
}

Это два взаимоисключающих варианта, первый только для pwsh, второй только для powershell.
У меня не было возможности проверить этот.

YuS_2 01-05-2021 01:00 2956811

Цитата:

Цитата Foreigner
первый только для pwsh, второй только для powershell. »

можно так:
Код:

$root = 'd:\test'
dir $root -file -rec|%{
    $bytes = [io.file]::readallbytes($_.fullname)
    [io.file]::writeallbytes($_.fullname, $bytes[1..($bytes.count-1)])
}


m0nkrus 01-05-2021 06:17 2956817

Наверное надо было уточнить... Пробую все это делать на семерке. Если нужно обязательно на десятке, то скажите, переключусь на нее.
Все скрипты вываливаются с ошибкой. С какой, сказать не могу, так как консольное окно сразу закрывается. Только и успеваю увидеть красный цвет надписи. С файлами в папке ничего не происходит. Еще раз прошу прощения за свою дурость, но с PowerShell я ранее дел не имел.

Iska 01-05-2021 07:33 2956818

Коллеги, судя по:
Цитата:

Цитата m0nkrus
…с PowerShell я ранее дел не имел. »

— вероятно, надо разрешить исполнение неподписанных локальных скриптов.

m0nkrus 01-05-2021 08:29 2956821

Iska, насколько я помню, в свое время я давал разрешение командой Set-ExecutionPolicy Unrestricted. Сейчас на всякий случай повторил. Результат не изменился...

m0nkrus 01-05-2021 08:44 2956823

Перешел на десятку. Скрипт ниже сработал, но не до конца. Не смог обработать файлы во вложенных папках. Выдал ошибку. В корневой для скрипта директории все обработал.
Код:

cd d:\test
foreach ($file in (Get-Childitem -File -Recurse))
{
    (Get-Content $file -Encoding byte -Raw)[1..($file.length-1)] | Set-Content $file -Encoding byte
}


А вот скрипт, что представлен ниже, выдал тот результат, что мне нужно!
Код:

$root = 'd:\test'
dir $root -file -rec|%{
    $bytes = [io.file]::readallbytes($_.fullname)
    [io.file]::writeallbytes($_.fullname, $bytes[1..($bytes.count-1)])
}

Благодарю всех за предложенные варианты!!!
Тему считаю исчерпанной.

YuS_2 01-05-2021 08:47 2956824

Цитата:

Цитата m0nkrus
Только и успеваю увидеть красный цвет надписи. »

Скрипт можно выполнить непосредственно в консоли, тогда она не будет закрыта и ошибку можно будет и прочитать, и скопировать.

m0nkrus 01-05-2021 08:51 2956825

YuS_2, не знал про это. Привык, что в cmd в консоль перенести готовый сценарий нельзя...

Ваш скрипт на семерке выдавал такую ошибку:
Код:

Get-ChildItem : Не удается найти параметр, соответствующий имени параметра "file".
строка:1 знак:16
+ dir $root -file <<<<  -rec|%{
    + CategoryInfo          : InvalidArgument: (:) [Get-ChildItem], ParameterBindingException
    + FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand

Get-ChildItem : Не удается найти параметр, соответствующий имени параметра "file".
строка:6 знак:16
+ dir $root -file <<<<  -rec|%{
    + CategoryInfo          : InvalidArgument: (:) [Get-ChildItem], ParameterBindingException
    + FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand


DJ Mogarych 01-05-2021 08:54 2956826

Судя по всему, у вас старый Powershell. Проверяется командой
Код:

host
Его можно обновить до версии 5.1
https://docs.microsoft.com/ru-ru/pow...powershell-7.1

YuS_2 01-05-2021 08:57 2956827

Цитата:

Цитата m0nkrus
Не удается найти параметр, соответствующий имени параметра "file". »

Это значит, что версия powershell 2.0, её надо обновить до 5.1, либо вместо параметра -file, в первом командлете, добавить в конвейер:
Код:

|?{!$_.PSIsContainer}
т.е. в целом, код выглядеть будет так:
Код:

$root = 'd:\test'
dir $root -rec|?{!$_.PSIsContainer}|%{
    $bytes = [io.file]::readallbytes($_.fullname)
    [io.file]::writeallbytes($_.fullname, $bytes[1..($bytes.count-1)])
}


m0nkrus 01-05-2021 09:06 2956828

DJ Mogarych, YuS_2, совершенно верно. Версия 2.0. Обновил до 5.1 и скрипты заработали корректно на семерке. Спасибо!

YuS_2 04-11-2021 18:32 2970715

Цитата:

Цитата m0nkrus
Задача не разовая, увы. »

Ну тогда, как-то так:
Код:

param (
        [string]$folder = '.\TEST'
)
function RW-Stream {
        param (
                [Parameter(ValueFromPipeline)]
                [ValidateNotNullOrEmpty()]
                $filein,
                $fileout = 'tmp.tmp'
        )
        begin {
                new-variable -name block -val 524288
                $buf = new-object byte[] ($block)
        }
        process {
                #measure-command{
                $reader = [io.streamreader]::new($filein.fullname)
                $writer = [io.streamwriter]::new($fileout)
                $reader.basestream.position = 1
                while ($reader.basestream.position -lt $reader.basestream.length){
                        $cnt = $reader.basestream.read($buf,0,$block)
                        $writer.basestream.write($buf,0,$cnt)
                }
                $reader.dispose();$writer.dispose()
                $reader.close();$writer.close()
                mi $fileout $filein.fullname -force
                #}
        }
}

dir $folder -file -rec|rw-stream

- скрипт принимает в качестве параметра наименование корневого каталога (можно указать абсолютный путь).
Корневой каталог сканируется рекурсивно. Целевые файлы заменяют исходные, то бишь копии нигде не создаются, поэтому применять осторожно, если исходные файлы потребуются в неизменном виде.

Файл ~250Мб, обрабатывается:
TotalSeconds : 7,5637454

Файл ~4,2Гб, обрабатывается:
TotalSeconds : 145,7682588

m0nkrus 04-11-2021 19:52 2970721

YuS_2, рекурсивно получаю ошибку:
Цитата:

You cannot call a method on a null-valued expression.
At E:\Design&Graphics\Unpack\onebyte.ps1:22 char:4
+ $cnt = $reader.basestream.read($buf,0,$block)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
Единственное, что менял в скрипте, это ".\TEST" заменил на "c:\test"

YuS_2 04-11-2021 20:49 2970730

Цитата:

Цитата m0nkrus
рекурсивно получаю ошибку »

Всё время забываю проверить на powershell v5.1, тестирую на pwsh 7.2, а у них есть различия...
В общем, там строчку надо удалить было
Код:

$filein = gi $filein
- она была нужна из расчета на то, чтобы в функцию можно было вместо объекта передавать строку с путем... но в варианте с командлетом Get-ChildItem (dir), она не критична и не нужна...
- в общем, тут в скрипте я уже исправил

m0nkrus 04-11-2021 21:18 2970731

YuS_2, честно говоря, я слегка в шоке! По скорости обработки этот скрипт по сравнению с прошлым, это как небо и земля. Спасибо огромное!

P.S. А можно на всякий случай еще скрипт со строчкой "$filein = gi $filein"? Когда-нибудь перейду на десятку, а там уже версия PowerShell будет актуальной.

YuS_2 04-11-2021 21:49 2970732

Цитата:

Цитата m0nkrus
Когда-нибудь перейду на десятку, а там уже версия PowerShell будет актуальной. »

Дык, pwsh v7.2 можно установить и на семерку (он вполне портабелен)... и они будут параллельно работать, не мешая друг другу...

Цитата:

Цитата m0nkrus
на всякий случай еще скрипт со строчкой "$filein = gi $filein"? »

Эта строка была, вот перед этой:
Код:

$reader = [io.streamreader]::new($filein.fullname)
Там можно условие добавить с проверкой версии powershell и не удалять её
Но, по сути, эта строка работала бы в случае вот такого вызова функции
Код:

rw-stream "d:\folder\file.ext"
то бишь, без неё вполне можно обойтись, просто в параметр вызова не давать строку, а сразу объект, например так:
Код:

$obj = gi "d:\folder\file.ext"
rw-stream $obj

и всё будет функционировать без этой строки...


Время: 17:29.

Время: 17:29.
© OSzone.net 2001-