Эхо указанных строк из текстового файла - PullRequest
1 голос
/ 09 января 2020

Это может быть вопрос XY, но я пытаюсь вывести на экран различные строки из текстового файла.

@setlocal enableextensions enabledelayedexpansion
@echo off
set /a "line = 0"
for /f "tokens=* delims= " %%a in (file.txt) do (
    set /a "line = line+1"
    if !line!==18 set thing1=%%a
    if !line!==19 set thing2=%%a
    if !line!==20 set thing3=%%a
)
endlocal & set thing1=%thing1% & set thing2=%thing2% & set thing3=%thing3%
echo:
echo %thing1%
echo %thing2%
echo %thing3%
pause

Это работает хорошо и аккуратно по сравнению с другими, которые я нашел, поэтому я был утомлен, чтобы сделать это более адаптируемо. Я могу сделать переменными номера строк, но что, если я хочу четыре строки или диапазон строк? Поэтому я попытался сделать для l oop. Перечислите все строки:

(
    echo @setlocal enableextensions enabledelayedexpansion
    echo @echo off
    echo set /a "line = 0"
    echo for /f "tokens=* delims= " %%a in (file.txt^) do (
        echo     set /a "line = line+1"
    )>>test.bat
    for /l %%m in (1,1,10) do (
        echo     if !line!==%%m set thing%%m=%%%%a
    )>>test.bat
    echo )>>test.bat
echo      endlocal ^& )>>test.bat
for /l %%m in (1,1,10) do (
    echo     set thing%%m^=%%thing%%%%m ^&  
)>>test.bat

Тогда я мог бы echo %thing(anynumber%), как я хотел. Это сталкивается с проблемами, когда список для l oop должен находиться в одной строке:

endlocal & set thing1=%thing1% & set thing2=%thing2% & set thing3=%thing3%

Вместо этого он выводит:

endlocal & 
    set thing1=%thing%1 & 
    set thing2=%thing%2 & 
    set thing3=%thing%3 & 
    etc...

Я знаю, prompt $H может вернуться назад, но я думаю, что это тупик для того, что я пытаюсь здесь. Я не могу найти много на обратной линии онлайн. Также он добавляет амперсанд к окончательному %%thing%% в списке.

Пример file.txt

This is line one
This is line two
This is line three
This is line four
This is line five
This is line six
This is line seven
This is line eight
This is line nine
This is line ten

Возможно, findstr - это способ go по этому поводу. Я нашел это и отредактировал, чтобы он соответствовал тому, что я пытался сделать:

:start
cls
set /p "line= Which lines?" 
for /f "tokens=*  delims=[] " %%a in ('type file.txt^|find /v /n ""') do (
    echo/%%a|findstr /l /b "%line%" >nul && echo/%%a
)
pause
goto :start

Но при вводе 1 он будет повторять каждый экземпляр, начинающийся с "1", то есть 1,11,12,13 et c. Это, кажется, почти там. Я пробовал различные переключатели с findstr /?, но не могу понять это. Если бы он мог также выполнять входные диапазоны, то входная строка 1-5,7,12-15 повторила бы их 10 строк.

Ответы [ 3 ]

2 голосов
/ 09 января 2020

Это должно сделать (хотя и не с диапазонами):

@echo off
setlocal 

set lines=1,5,6,8
(for %%a in (%lines%) do echo %%a:)>lines.txt

for /f "tokens=1,* delims=:" %%a in ('type file.txt^|findstr /n "^"^|findstr /bg:lines.txt') do echo/%%b
del lines.txt

Первый for l oop создает временный файл для findstr /g (подробности см. findstr /?).
Второй добавляет номера строк, ищет их в файле и печатает исходную строку, если номер строки находится в файле.

Числа в %lines% могут быть разделены любыми стандартными разделителями (TAB, ПРОБЕЛЫ, запятые и даже = (не рекомендуется - оставайтесь с пробелами и / или запятыми)

Чтобы перейти к диапазонам 5-10, вам нужно проанализировать %lines% с еще большим кодом (трудно сделать это надежным) и «перевести» в однострочные номера для записи в lines.txt

(Мы могли бы также расширить %lines% до строки поиска REGEX или findstr, избегая временного файла, но это намного проще понять и поддерживать таким образом)

Редактировать: реализовано простое «расширение диапазона» (без проверки на достоверность):

@echo off 
setlocal 

set "lines=1,4-6,9"

(for %%a in (%lines%) do (
  echo %%a|find "-" >nul && call :range %%a || echo/%%a:
))>lines.txt

echo lines %lines% are:
for /f "tokens=1,* delims=:" %%a in ('type file.txt^|findstr /n "^"^|findstr /bg:lines.txt') do echo/%%b
del lines.txt
goto :eof

:range
for /f "tokens=1,2 delims=-" %%b in ("%1") do (
  for /l %%i in (%%b,1,%%c) do echo %%i:
)
goto :eof

Вывод (с ваш пример входного файла):

lines 1,4-6,9 are:
This is line one
This is line four
This is line five
This is line six
This is line nine

PS: это выводит строки в исходном порядке (set "lines=1,4-6,8" и set "lines=8 1 4-6" дают одинаковый вывод (из-за того, как findstr /g работает))

0 голосов
/ 10 января 2020

Сокращает количество строк в верхней или нижней части файла.

Это похоже на команду Unix '* Tail, для которой нет эквивалента Windows'.

Для использования

Вырезать

cut {t|b} {i|x} NumOfLines

Обрезает количество строк сверху или снизу файла.

t - top of the file
b - bottom of the file
i - include n lines
x - exclude n lines

Пример

 cscript //nologo c:\folder\cut t i 5 < "%systemroot%\win.ini"

Скопировать следующие строки в cut.vbs

Set Arg = WScript.Arguments
set WshShell = createObject("Wscript.Shell")
Set Inp = WScript.Stdin
Set Outp = Wscript.Stdout
Set rs = CreateObject("ADODB.Recordset")
With rs
    .Fields.Append "LineNumber", 4 
    .Fields.Append "Txt", 201, 5000 
    .Open
    LineCount = 0
    Do Until Inp.AtEndOfStream
        LineCount = LineCount + 1
        .AddNew
        .Fields("LineNumber").value = LineCount
        .Fields("Txt").value = Inp.readline
        .UpDate
    Loop

    .Sort = "LineNumber ASC"

    If LCase(Arg(1)) = "t" then
        If LCase(Arg(2)) = "i" then
            .filter = "LineNumber < " & LCase(Arg(3)) + 1
        ElseIf LCase(Arg(2)) = "x" then
            .filter = "LineNumber > " & LCase(Arg(3))
        End If
    ElseIf LCase(Arg(1)) = "b" then
        If LCase(Arg(2)) = "i" then
            .filter = "LineNumber > " & LineCount - LCase(Arg(3))
        ElseIf LCase(Arg(2)) = "x" then
            .filter = "LineNumber < " & LineCount - LCase(Arg(3)) + 1
        End If
    End If

    Do While not .EOF
        Outp.writeline .Fields("Txt").Value

        .MoveNext
    Loop
End With

Для программы подсчета строк

Set Arg = WScript.Arguments
set WshShell = createObject("Wscript.Shell")
Set Inp = WScript.Stdin
Set Outp = Wscript.Stdout
Do Until Inp.AtEndOfStream
    Line=Inp.readline
    Count = Count +1
Loop
outp.writeline Count
0 голосов
/ 10 января 2020

Я не совсем понимаю массивы. У меня будет еще один взгляд на следующей неделе. До сих пор у меня это основано на ответе @Stephan.

choice /c rs /m "RANGE MODE OR SPECIFIED MODE"
goto:%errorlevel%
:2
:specified
echo:
set /p lines=ENTER SPECIFIC LINES (seperated by spaces)? 
(for %%a in (%lines%) do echo %%a:)>lines.txt
for /f "tokens=1,* delims=:" %%a in (
    'type file.txt^|findstr /n "^"^|findstr /bg:lines.txt'
    ) do (
    echo/%%b)
del lines.txt
pause
goto :eof

:1
:range
echo:
set /p ran=ENTER RANGE (e.g. 15-25)? 
echo %ran%>range.txt
for /f "tokens=1,* delims=-" %%a in (range.txt) do (
    set line1=%%a
    set line2=%%b)
del range.txt
(for /l %%a in (%line1%,1,%line2%) do echo %%a:)>lines.txt
for /f "tokens=1,* delims=:" %%a in (
    'type file.txt^|findstr /n "^"^|findstr /bg:lines.txt'
    ) do (
    echo/%%b)
del lines.txt
pause
goto :eof

Попытка проследить за массивами через по этой ссылке Я вижу, когда задаю элементы в пакете, но не указываю file.txt , Я пытался

for /f %%a in ('type file.txt^|echo !elem[%2%]!') do echo %%a

и

      for /f "tokens=*  delims=" %%a in ('type file.txt^|find /v /n ""') do (
    echo/%%a|findstr /l /b "!elem[%2%]!" >nul && echo echo/%%a)

В любом случае, это другой вопрос, у меня есть работа по этой ссылке на следующей неделе.

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