Компьютерный форум 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=278100)

ivanxam 20-02-2014 16:03 2312501

Как удалить последнюю строку в текстовом файле?
 
Добрый день, люди добрые помогите, что-то я вообще запутался.
Как удалить последнюю строку в файле? Строку эту я знаю.

Файл 100001.txt
Код:

20140201.jrn
20140202.jrn
20140203.jrn
20140204.jrn
20140205.jrn
20140206.jrn
20140207.jrn
20140208.jrn
20140209.jrn
20140210.jrn

Или можно выполнить dir без последней строки(файла)

Georgio 21-02-2014 11:56 2312951

Цитата:

Цитата ivanxam
что-то я вообще запутался »

Решить эту задачу в общем виде (т. е. и с учётом пустых строк, и без потери символов) на языке командной строки действительно сложно.


Цитата:

Цитата ivanxam
Строку эту я знаю »

А что изменится в решении, если Вы эту строку не знаете?


Цитата:

Цитата ivanxam
Как удалить последнюю строку в файле? »

В Вашем случае так:

Код:

@echo off
for /f "usebackq" %%i in ("100001.txt") do (
 set /a m+=1
)
(
for /f "usebackq delims=" %%i in ("100001.txt") do (
 set /a n+=1
 call echo %%n%%|>nul findstr /vxc:%m%&& echo %%i
))>.tmp
move .tmp "100001.txt">nul


Цитата:

Цитата ivanxam
Или можно выполнить dir без последней строки(файла) »

Можно ли выполнить команду "dir", чтобы в её выводе не было последней строки?

Вариант №1.

Код:

@echo off
for /f "delims=" %%i in ('dir /a-d /b *.jrn') do (
 set /a m+=1
)
(
for /f "delims=" %%i in ('dir /a-d /b *.jrn') do (
 set /a n+=1
 call echo %%n%%|>nul findstr /vxc:%m%&& echo %%i
))>"100001.txt"

Вариант №2.

Код:

@echo off
for %%i in (*.jrn) do (
 set /a m+=1
 >nul dir /a-d /b %%i
)
(
for %%i in (*.jrn) do (
 set /a n+=1
 call echo %%n%%|>nul findstr /vxc:%m%&& dir /a-d /b %%i
))>"100001.txt"

Вариант №3.

Если в выводе нужны только имена файлов с расширениями (как у Вас), то можно обойтись без команды "dir".

Код:

@echo off
for %%i in (*.jrn) do (
 set /a m+=1
)
(
for %%i in (*.jrn) do (
 set /a n+=1
 call echo %%n%%|>nul findstr /vxc:%m%&& echo %%i
))>"100001.txt"


P. S. Команда "@echo off" обязательна во всех приведённых кодах.

sov44 21-02-2014 12:46 2312984

Вариант 4
Код:

@echo off

for /f "delims=" %%a in (out.txt) do set "old=%%a"
findstr /vc:"%old%" "out.txt">>new.txt


Georgio 21-02-2014 14:07 2313046

sov44, а если в выводе команды, например, такой:
Код:

for /f "tokens=*" %%i in ('dir /a-d /b /s') do echo %%~nxi
, таких "%old%" будет несколько?

По этой причине я не рассматривал этот вариант.

Iska 21-02-2014 14:25 2313057

Я бы попробовал так:
читать дальше »
Код:

@echo off
setlocal enableextensions enabledelayedexpansion

set sSourceFile=C:\Песочница\040\100001.txt

call :GetTemporaryName

if exist "%sSourceFile%" (
        for /f "usebackq delims=" %%i in (
                `type "%sSourceFile%"^|find.exe /v /c ""`
        ) do set /a iTotalLines = %%i

        set /a iNeedLines = iTotalLines - 1

        >"%TemporaryName%" (
                for /f "usebackq tokens=1* delims=[]" %%i in (
                        `type "%sSourceFile%"^|find.exe /v /n ""`
                ) do if %%i leq !iNeedLines! echo.%%j
        )

        >nul copy /y "%sSourceFile%" "%sSourceFile%.bak"
        >nul copy /y "%TemporaryName%" "%sSourceFile%"
        del /f /q "%TemporaryName%"
) else (
        echo Source file [%sSourceFile%] not found.
        exit /b 1
)

endlocal
exit /b 0
rem ==========================================================================

rem ==========================================================================
rem Функция GetTemporaryName()
rem
rem Серый форум / CMD/BAT: генерация пути для временного файла или папки
rem (http://forum.script-coding.com/viewtopic.php?id=6259)
rem ==========================================================================
:GetTemporaryName
    setlocal enableextensions enabledelayedexpansion

:NextName
    set sTempName=%temp%\temp%random%.tmp

    if exist "%sTempName%" goto :NextName

    set sProcName=%~0

    endlocal & set %sProcName:~4%=%sTempName%
    exit /b 0
rem ==========================================================================


ivanxam 21-02-2014 14:42 2313074

Всем огромное спасибо.

sov44 21-02-2014 17:26 2313206

Цитата:

Цитата Georgio
sov44, а если в выводе команды, например, такой: »

Цитата:

Цитата ivanxam
Как удалить последнюю строку в файле? »

Georgio, т.з. сформулировано чётко.

вторую часть вопроса не рассматривал, т. к. не понятно. по какому критерию считать последнюю строку
Цитата:

Цитата ivanxam
выполнить dir без последней строки(файла) »


megaloman 21-02-2014 18:16 2313248

Прямолинейно
Код:

@Echo Off

Set "File=100001.txt"

SetLocal EnableExtensions EnableDelayedExpansion

Set /A N=0
FOR /F "usebackq delims=" %%i in (`Type "%File%"`) do Set /A N+=1

Set /A M=%N%

Set /A N=0
FOR /F "usebackq delims=" %%i in (`Type "%File%"`) do Set /A N+=1 & If !N!==1 (Echo %%i>"%File%") Else (If !N! LSS %M% Echo %%i>>"%File%")

Не очень понял насчет Dir без последней строки. Вы что, командой Dir в файл 100001.txt заносите имена файлов? А у файлов имена ГГГГММДД.JRN ? Тогда возможно более короткое решение ...

Iska 21-02-2014 18:33 2313259

Цитата:

Цитата megaloman
Прямолинейно »

megaloman, тут опять вопрос с пропуском пустых строк при разборе по «for /f». В данном конкретном случае (разбор «dir /b») сие, конечно, не существенно.

Цитата:

Цитата megaloman
Вы что, командой Dir в файл 100001.txt заносите имена файлов? »

Я понял, что так.

Цитата:

Цитата megaloman
Тогда возможно более короткое решение ... »

Выкладывайте, конечно.

megaloman 21-02-2014 19:10 2313284

Опять прямолинейно, если в файле 100001.txt не важен порядок (по убыванию-возрастанию)
Код:

@Echo Off

Set "File=100001.txt"
Set "Mask=20??????.jrn"

Del "%File%" 2>Nul
FOR /F "skip=1 usebackq delims=" %%i in (`Dir "%Mask%" /b /A:-D /O:-N  2^>nul`) Do Echo %%i>>"%File%"

Увы, если важен порядок, придётся добавить за этим приведенным кодом сортировку, что не короче предыдущего решения
Код:

SetLocal EnableExtensions EnableDelayedExpansion
Set /A N=0
FOR /F "usebackq delims=" %%i in (`Type "%File%"^|Sort`) Do Set /A N+=1 & If !N!==1 (Echo %%i>"%File%") Else (Echo %%i>>"%File%")


megaloman 21-02-2014 19:51 2313303

Можно извратиться вот так, при этом последнее имя файла из Dir не попадёт в текстовый файл
Код:

@Echo Off

Set "File=100001.txt"
Set "Mask=20??????.jrn"

SetLocal EnableExtensions EnableDelayedExpansion

Set "String='"
FOR /F "usebackq delims=" %%i in (`Dir "%Mask%" /b /A:-D /O:N 2^>nul`) Do If !String!==' (Set "String=%%i"&Del "%File%" 2>Nul) Else (Echo !String!>>"%File%"&Set "String=%%i")

Или, чтобы легче читалось, то же самое
Код:

@Echo Off

Set "File=100001.txt"
Set "Mask=20??????.jrn"

SetLocal EnableExtensions EnableDelayedExpansion

Set "String='"
FOR /F "usebackq delims=" %%i in (`Dir "%Mask%" /b /A:-D /O:N 2^>nul`) Do (
        If !String!==' (
                Set "String=%%i"
                Del "%File%" 2>Nul
        ) Else (
                Echo !String!>>"%File%"
                Set "String=%%i"
        )
)

Или, если вернуться к изначальной теме "Как удалить последнюю строку в текстовом файле?", то на этой же идее
Код:

@Echo Off

Set "File=100001.txt"

SetLocal EnableExtensions EnableDelayedExpansion

Set "String='"
FOR /F "usebackq delims=" %%i in (`Type "%File%"`) Do If !String!==' (Set "String=%%i"&Del "%File%" 2>Nul) Else (Echo !String!>>"%File%"&Set "String=%%i")


Georgio 21-02-2014 20:19 2313323

"Немного экзотики"...

Использование команды "fc":

Код:

@echo off
set text_file=100001.txt
for /f %%i in ('find /c /v ""^<"%text_file%"') do set /a n=%%i-1
>nul copy nul 0.tmp
>1.tmp fc /lb%n% 0.tmp "%text_file%"
>2.tmp<1.tmp more +4
>3.tmp<2.tmp find /v "*****"
del 0.tmp 1.tmp 2.tmp
>nul move "%text_file%" "%text_file%.bak"
>nul move 3.tmp %text_file%

Жаль только, что слишком длинные строки команда "fc" располагает в несколько строк.

В случае использования только двух временных файлов в конце переписанного файла будут две лишние пустые строки:

Код:

@echo off
set text_file=100001.txt
for /f %%i in ('find /c /v ""^<"%text_file%"') do set /a n=%%i-1
>nul copy nul 0.tmp
fc /lb%n% 0.tmp "%text_file%"| more +4|>1.tmp find /v "*****"
del 0.tmp
>nul move "%text_file%" "%text_file%.bak"
>nul move 1.tmp %text_file%


Anufriev 14-09-2018 10:05 2831298

Цитата:

Цитата megaloman
)
Или, если вернуться к изначальной теме "Как удалить последнюю строку в текстовом файле?", то на этой же идее
Код:

@Echo Off
Set "File=100001.txt"
SetLocal EnableExtensions EnableDelayedExpansion
Set "String='"
FOR /F "usebackq delims=" %%i in (`Type "%File%"`) Do If !String!==' (Set "String=%%i"&Del "%File%" 2>Nul) Else (Echo !String!>>"%File%"&Set "String=%%i")

»

День добрый, данный батник хорошо работает, если обрабатывать только один файл

вопрос, а как его подправить, что бы он обрабатывал несколько файлов?

megaloman 14-09-2018 12:19 2831312

Anufriev, Неужели это я писал? Задача решалась применительно к конкретной ситуации (это я свою совесть успокаиваю). Боюсь, возможны косяки, если есть пустые строки и всякие спецсимволы.
Цитата:

Цитата Anufriev
что бы он обрабатывал несколько файлов? »

- не понимаю, что за файлы и где, как имена задаются.
Если тупо и не думать, организуем процедуру и в неё будем передавать имена файлов
Код:

@Echo Off
        SetLocal EnableExtensions EnableDelayedExpansion
        Call :LastDel "100001.txt"
        Call :LastDel "D:\тра ля ля\1200001.txt"
        Call :LastDel "\\Server\Share\ogogo.ini"
GoTo :Eof

:LastDel
        Set "File=%~1"
        Set "String='"
        FOR /F "usebackq delims=" %%i in (`Type "%File%"`) Do If !String!==' (Set "String=%%i"&Del "%File%" 2>Nul) Else (Echo !String!>>"%File%"&Set "String=%%i")
GoTo :Eof

Не тестировал.
Если это все файлы по какой-то маске в определённой папке, возможно организация For c тем же вызовом процедуры - уточните задачу, если надо. Опять же, работая с текстом в CMD, можно хорошо вляпаться.

YuS_2 14-09-2018 20:20 2831366

Цитата:

Цитата megaloman
Опять же, работая с текстом в CMD, можно хорошо вляпаться. »

Дык, почему бы не воспользоваться powershell?
Код:

$arr = dir *.txt #либо прописываем массив с конкретными файлами, имеющими различные пути и расширения.
$arr|%{$a = gc $_.fullname;$a|select -skiplast 1|sc $_.fullname}


Anufriev 15-09-2018 06:21 2831401

Цитата:

Цитата YuS_2
Цитата megaloman:
Опять же, работая с текстом в CMD, можно хорошо вляпаться. »
Дык, почему бы не воспользоваться powershell?
Код:

$arr = dir *.txt #либо прописываем массив с конкретными файлами, имеющими различные пути и расширения.
$arr|%{$a = gc $_.fullname;$a|select -skiplast 1|sc $_.fullname}

-------
scio me nihil scire »

увы, не везде и не всегда можно использовать что-то лучше cmd:(

Цитата:

Цитата megaloman
Не тестировал.
Если это все файлы по какой-то маске в определённой папке, возможно организация For c тем же вызовом процедуры - уточните задачу, если надо. Опять же, работая с текстом в CMD, можно хорошо вляпаться. »

простите, что не конкретно описал

файлы имеют маску *.xml
находятся в одной папке, при удалении строки копируются в другую папку
содержимое разнообразное, но всегда нужно удалить последнюю строку (подпись) она тоже меняется

p.s. может и правда отдельную тему создать, что-бы людям проще было найти (я посчитал, что можно небольшой корректировкой кода обойтись, наивный?) :)

YuS_2 15-09-2018 13:42 2831425

Цитата:

Цитата Anufriev
увы, не везде и не всегда можно использовать что-то лучше cmd »

увы, это так.
Но что мешает стремиться к лучшему? :)

Iska 15-09-2018 17:10 2831476

Ориентироваться на строки в xml-файлах… Я бы не стал.

Anufriev 17-09-2018 05:08 2831701

Вложений: 1
Цитата:

Цитата megaloman
Anufriev, дайте хотя бы один файл для примера, переименуйте его в txt и прикрепите к сообщению
Сильно сомневаюсь, что для xml »

Утро доброе, прошу

p.s. Естественно данный занулены

Iska 17-09-2018 05:50 2831702

Цитата:

Цитата Anufriev
но всегда нужно удалить последнюю строку (подпись) она тоже меняется »

Скажите, коллега, подпись всегда одна и та же? А если могут быть разные — не попадётся ли как-нибудь однажды в подписи символ 0x0A или 0x0D, сиречь LineFeed, або CarriageReturn? Тройку нулевых символов я там уже вижу.

Цитата:

Цитата Anufriev
увы, не везде и не всегда можно использовать что-то лучше cmd »

Ну, WSH везде есть.
Скрытый текст
Код:

Option Explicit

Dim strSourceFolder

Dim objFSO
Dim objFile

Dim arrContent


If WScript.Arguments.Count = 1 Then
        strSourceFolder = WScript.Arguments.Item(0)
       
        Set objFSO = WScript.CreateObject("Scripting.FileSystemObject")
       
        If objFSO.FolderExists(strSourceFolder) Then
                For Each objFile In objFSO.GetFolder(strSourceFolder).Files
                        If StrComp(objFSO.GetExtensionName(objFile.Name), "xml", 0) = 0 Then
                                With objFSO.OpenTextFile(objFile.Path)
                                        arrContent = Split(.ReadAll(), vbCrLf)
                                        .Close
                                End With
                               
                                ReDim Preserve arrContent(UBound(arrContent) - 1)
                               
                                objFile.Copy objFSO.BuildPath(strSourceFolder, objFSO.GetBaseName(objFile.Name) & ".bak"), True
                               
                                With objFSO.CreateTextFile(objFile.Path, True)
                                        .Write Join(arrContent, vbCrLf) & vbCrLf
                                        .Close
                                End With
                        Else
                                ' Nothing to do
                        End If
                Next
        Else
                WScript.Echo "Can't find source folder [" & strSourceFolder & "]."
                WScript.Quit 2
        End If
       
        Set objFSO = Nothing
Else
        WScript.Echo "Usage: cscript.exe //nologo """ & WScript.ScriptName & """ <Source folder>"
        WScript.Quit 1
End If

WScript.Quit 0

Путь к целевому каталогу указывается параметром скрипта (также можно просто перетащить папку на скрипт в Проводнике). Для каждого обработанного xml-файла создаётся резервная копия .bak.

Anufriev 17-09-2018 06:18 2831704

Цитата:

Цитата Iska
Скажите, коллега, подпись всегда одна и та же? А если могут быть разные — не попадётся ли как-нибудь однажды в подписи символ 0x0A или 0x0D, сиречь LineFeed, або CarriageReturn? Тройку нулевых символов я там уже вижу. »

Подпись может меняться, эм... не, не встречал я таких символов

Цитата:

Цитата Iska
Ну, WSH везде есть. »

Есть то она есть, но у нас беда с ИБ, прилетает по шапке и доказать, что это необходимо в работе практически не возможно, не любят они скрипты на пользовательских компах...

Iska 17-09-2018 06:45 2831706

Цитата:

Цитата Anufriev
не любят они скрипты на пользовательских компах... »

Если они такие умные не любят — пусть принимают скрипты, проверяют, снабжают своей цифровой подписью и возвращают вобрат для использования. А mshta.exe они ещё случайно не запретили пользовать, а?

Anufriev 17-09-2018 06:52 2831708

Цитата:

Цитата Iska
А mshta.exe они ещё случайно не запретили пользовать, а? »

пока что не добрались))))

YuS_2 17-09-2018 07:53 2831711

Цитата:

Цитата Iska
Ну, WSH везде есть. »

ms-dos, win 3.11, win 95? :search: :)

Iska 17-09-2018 10:14 2831720

YuS_2, я имел в виду — из нонешних ОС.

YuS_2 17-09-2018 11:09 2831729

Цитата:

Цитата Iska
нонешних ОС. »

дык, нонешние это уже семерка, восьмерка да десятка (там posh везде есть)... а остальные в музей пора передавать, на вечное хранение :)

Iska 17-09-2018 11:19 2831730

YuS_2, смотря где. У меня и Windows NT 4.0 Workstation не так давно были вполне рабочими станциями. Что делать… За неимением гербовой — пишем на простой :(.

megaloman 17-09-2018 11:53 2831733

Anufriev, с голым CMD Ваша задача вряд ли может быть решена. Если принять, как в вашем примере, что строки разделяются символами 0D 0A (то есть 13 10) и последняя строка этими символами не завершается, в подписи эта парочка не присутствует, то
Вот cmd с привлечением js
Код:

@set @E=1; /*
@Echo Off
        cls
       
        Set "BoxIn=Z:\Box_In"
        Set "BoxOut=Z:\Box_Out"
        Set "Mask=*.xml"
       
        FOR %%f IN ("%BoxIn%\%Mask%") DO (
                Copy "%%f" "%BoxOut%\" >nul
                Call Cscript //NoLogo /E:jscript "%~dpnx0" "%BoxOut%\%%~nxf"
        )
        pause
GoTo :Eof

*/
var oArg = WScript.Arguments;
var nArg = oArg.Count();

if (nArg != 1) {
        WScript.Echo("Error! Invalid number of arguments!");
        WScript.Quit(1);
}

var FText=oArg(0);

var FSO=WScript.CreateObject("Scripting.FileSystemObject");

var InFile;
try {InFile = FSO.OpenTextFile(FText,1);}
catch (e) {
  if (e !=0 ) {
        WScript.Echo("Error! " + FText + "  " + e.description);
              WScript.Quit(2);
    }
}
var TextAll = InFile.ReadAll();
InFile.Close();

var Nlast=TextAll.lastIndexOf(String.fromCharCode(13,10));
TextAll=TextAll.substr(0,Nlast);

InFile = FSO.OpenTextFile(FText,2);
InFile.Write(TextAll);
InFile.Close();

WScript.Quit(0);

Пропишите пути к вашим входной и выходной папкам.

megaloman 17-09-2018 12:51 2831742

Тихий ужас! Я не понимаю как, но это на представленном примере работает :(
Код:

@Echo Off
        Set "BoxIn=Z:\Box_In"
        Set "BoxOut=Z:\Box_Out"
        Set "Mask=*.xml"
       
        FOR %%f IN ("%BoxIn%\%Mask%") DO (
                >"%BoxOut%\%%~nxf" (FOR /F "usebackq delims=" %%t IN ("%%f") DO @echo.%%t)
        )
GoTo :Eof

Возможно, из-за какого-то непристойного символа в подписи
Гарантировать, что это будет работать всегда, не берусь.

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

@Echo Off
        Set "BoxIn=Z:\Box_In"
        Set "BoxOut=Z:\Box_Out"
        Set "Mask=*.xml"
        Set "End=</ESDT_BNK>"
       
        FOR %%f IN ("%BoxIn%\%Mask%") DO Call :Restrict "%%f"
GoTo :Eof

:Restrict
        >"%BoxOut%\%~nx1" (FOR /F "usebackq delims=" %%t IN (%1) DO (@echo.%%t) &If /I "%End%"=="%%t" GoTo :Eof)
GoTo :Eof


Iska 17-09-2018 13:26 2831748

Цитата:

Цитата megaloman
Возможно, из-за какого-то непристойного символа в подписи »

Из-за тех самых нулевых символов (0x00) в подписи, надо полагать. Стоит их убрать — и подпись остаётся на месте.

Anufriev 17-09-2018 13:57 2831752

Цитата:

Цитата megaloman
А так, наверное, более предсказуемо:

Код:

@Echo Off
 Set "BoxIn=Z:\Box_In"
 Set "BoxOut=Z:\Box_Out"
 Set "Mask=*.xml"
 Set "End=</ESDT_BNK>"
FOR %%f IN ("%BoxIn%\%Mask%") DO Call :Restrict "%%f"
GoTo :Eof
:Restrict
 >"%BoxOut%\%~nx1" (FOR /F "usebackq delims=" %%t IN (%1) DO (@echo.%%t) &If /I "%End%"=="%%t" GoTo :Eof)
GoTo :Eof »


Взял потестировать этот, пока что работает хорошо, будем понаблюдать))) спасибо огромное!

p.s. пойду свечку поставлю, что бы так работал постоянно)

YuS_2 17-09-2018 14:49 2831755

Удаление любого количества строк от конца текста:
Код:

@echo off
set "infile=files.txt"
set "outfile=out.txt"

rem количество удаляемых строк
set k=1

for /f %%a in ('^<"%infile%" more^|find /v /c ""') do set n=%%a
set /a n-=k+1

(for /l %%i in (0,1,%n%) do (
        more +%%i "%infile%"|set /p x=^&cmd /v/c "if defined x (echo.!x!) else (echo.)"
))>"%outfile%"


alpap 17-09-2018 18:04 2831794

Цитата:

Цитата YuS_2
Удаление любого количества строк от конца текста: »

можно и короче:
Код:

@echo off
set cns=3
<"file.txt">+ (sort /+2147483647|more +%cns%|sort /+2147483647|findstr /vrc:"^$")& move+ "file.txt"
exit


YuS_2 17-09-2018 18:37 2831799

Цитата:

Цитата alpap
можно и короче »

промежуточный файл дает значительный прирост скорости :up
только пустые строки съедает...
лучше "findstr ..." заменить на "more +1", правда пустая строка лишняя добавляется в конец файла, но это, наверное, не проблема для .xml

alpap 17-09-2018 20:19 2831812

Цитата:

Цитата YuS_2
промежуточный файл дает значительный прирост скорости »

согласен, но на удивление sort работает быстро.

YuS_2 18-09-2018 08:33 2831852

Цитата:

Цитата alpap
на удивление sort работает быстро. »

Тут скорее заслуга не sort. В твоем примере одна команда обрабатывает весь массив текста сразу, в отличие от моего (построчная обработка), что и дает тот самый прирост. Жаль, что в cmd отсутствуют полноценные конвейеры, тогда промежуточный файл не понадобился бы, да и скорость обработки была бы ещё выше...


Время: 18:47.

Время: 18:47.
© OSzone.net 2001-