Каковы недокументированные функции и ограничения команды Windows FINDSTR?

Команда Windows FINDSTR ужасно задокументирована. Существует очень простая справка по командной строке, доступная через FINDSTR/? или HELP FINDSTR, но это крайне неадекватно. На сайте https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/findstr можно найти немного больше документации.

Существует множество функций и ограничений FINDSTR, которые даже не упоминаются в документации. Их нельзя было ожидать без предварительного знания и/или тщательного экспериментирования.

Итак, вопрос в том, каковы недокументированные особенности и ограничения FINDSTR?

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

А) Разработчики могут в полной мере воспользоваться возможностями, которые там есть.

Б) Разработчики не тратят свое время на размышления о том, почему что-то не работает, когда кажется, что должно.

Пожалуйста, убедитесь, что вы знаете существующую документацию, прежде чем отвечать. Если информация покрыта ПОМОЩЬЮ, то она здесь не принадлежит.

Также это не место, чтобы показать интересные применения FINDSTR. Если логический человек может предвидеть поведение конкретного использования FINDSTR на основе документации, то он не относится к этому.

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

Ответ 1

Введение
Большая часть информации в этом ответе была собрана на основе экспериментов, проведенных на компьютере с Vista. Если прямо не указано иное, я не подтвердил, применима ли эта информация к другим версиям Windows.

Вывод FINDSTR
Документация никогда не объясняет вывод FINDSTR. Это намекает на то, что печатаются совпадающие строки, но не более того.

Формат соответствия строки выводится следующим образом:

Имя файла: LINENUMBER: lineOffset: текст

где

fileName:= Имя файла, содержащего совпадающую строку. Имя файла не печатается, если запрос был явно для одного файла, или при поиске вводимых по pipeопроводу входов или перенаправленных входных данных. При печати fileName всегда будет содержать любую предоставленную информацию о пути. Дополнительная информация о пути будет добавлена, если используется опция /S. Печатный путь всегда указывается относительно предоставленного пути или относительно текущего каталога, если он не указан.

Примечание. Префикса имени файла можно избежать при поиске в нескольких файлах с помощью нестандартных (и плохо документированных) подстановочных знаков < и >. Точные правила работы этих подстановочных знаков можно найти здесь. Наконец, вы можете посмотреть на этот пример того, как нестандартные символы подстановки работают с FINDSTR.

lineNumber:= Номер строки совпадающей строки, представленной в виде десятичного значения, где 1 представляет 1-ю строку ввода. Распечатывается, только если указана опция /N.

lineOffset:= десятичное смещение байта начала совпадающей строки, где 0 представляет 1-й символ 1-й строки. Распечатывается, только если указана опция /O. Это не смещение совпадения в строке. Это число байтов от начала файла до начала строки.

text= Двоичное представление совпадающей строки, включая любые & lt; CR> и/или & lt; LF>. Ничего не осталось из двоичного вывода, так что этот пример, который соответствует всем строкам, даст точную двоичную копию исходного файла.

FINDSTR "^" FILE >FILE_COPY

Большинство управляющих символов и множество расширенных символов ASCII отображаются в XP в виде точек
FINDSTR на XP отображает большинство непечатаемых управляющих символов из соответствующих строк в виде точек (точек) на экране. Следующие управляющие символы являются исключениями; они отображаются как сами: вкладка 0x09, перевод строки 0x0A, вертикальная вкладка 0x0B, подача формы 0x0C, возврат каретки 0x0D.

XP FINDSTR также преобразует ряд расширенных символов ASCII в точки. Символы расширенного ASCII, которые отображаются в XP как точки, такие же, как те, которые преобразуются при вводе в командной строке. См. раздел "Ограничения символов для параметров командной строки - Расширенное преобразование ASCII", далее в этом посте

Управляющие символы и расширенный ASCII не преобразуются в точки в XP, если выходные данные передаются по конвейеру, перенаправляются в файл или в предложении FOR IN().

Vista и Windows 7 всегда отображают все символы как сами по себе, а не как точки.

Коды возврата (ОШИБКА)

Источник данных для поиска (Обновлено на основе тестов с Windows 7)
Findstr может искать данные только из одного из следующих источников:

  • имена файлов, указанные в качестве аргументов и/или с использованием опции /F:file.

  • стандартный ввод через перенаправление findstr "searchString" <file

  • поток данных из канала type file | findstr "searchString"

Аргументы/параметры имеют приоритет над перенаправлением, которое имеет приоритет над переданными данными.

Аргументы имени файла и /F:file могут быть объединены. Можно использовать несколько аргументов имени файла. Если указано несколько опций /F:file, то используется только последний. Подстановочные знаки допускаются в аргументах имени файла, но не в пределах файла, на который указывает /F:file.

Источник строк поиска (обновлено на основе тестов в Windows 7)
Опции /G:file и /C:string могут быть объединены. Можно указать несколько опций /C:string. Если указано несколько опций /G:file, то используется только последний. Если используется /G:file или /C:string, то все аргументы, не являющиеся опциями, предполагаются как файлы для поиска. Если ни /G:file, ни /C:string не используются, то первый неопциональный аргумент обрабатывается как список поисковых терминов, разделенных пробелом.

Имена файлов не должны заключаться в кавычки внутри файла при использовании опции /F:FILE.
Имена файлов могут содержать пробелы и другие специальные символы. Большинство команд требуют, чтобы такие имена файлов были заключены в кавычки. Но опция FINDSTR /F:files.txt требует, чтобы имена файлов в файле files.txt НЕ цитировались. Файл не будет найден, если имя указано в кавычках.

BUG - короткие 8.3 имена файлов могут нарушать опции /D и /S
Как и для всех команд Windows, FINDSTR будет пытаться сопоставить как длинное имя, так и короткое имя 8.3 при поиске файлов для поиска. Предположим, что текущая папка содержит следующие непустые файлы:

b1.txt
b.txt2
c.txt

Следующая команда успешно найдет все 3 файла:

findstr /m "^" *.txt

b.txt2 совпадает, поскольку соответствующее короткое имя B9F64~1.TXT совпадает. Это согласуется с поведением всех других команд Windows.

Но ошибка с опциями /D и /S приводит к тому, что следующие команды находят только b1.txt

findstr /m /d:. "^" *.txt
findstr /m /s "^" *.txt

Ошибка не позволяет найти b.txt2, а также все имена файлов, которые сортируются после b.txt2 в одном и том же каталоге. Найдены дополнительные файлы, которые сортируются ранее, например, a.txt. Дополнительные файлы, которые сортируются позже, такие как d.txt, пропускаются после того, как ошибка была вызвана.

Каждый найденный каталог обрабатывается независимо. Например, опция /S может успешно начать поиск в дочерней папке, если не удается найти файлы в родительской папке, но как только ошибка приводит к отсутствию короткого имени файла в дочерней папке, тогда все последующие файлы в этой дочерней папке будут также будет пропущено.

Команды работают без ошибок, если на компьютере с отключенной генерацией имен NTFS 8.3 созданы одинаковые имена файлов. Конечно, b.txt2 не будет найден, но c.txt будет найден правильно.

Не все короткие имена вызывают ошибку. Все случаи ошибочного поведения, которые я видел, включают расширение длиной более 3 символов с коротким именем 8.3, которое начинается так же, как и обычное имя, которое не требует имени 8.3.

Ошибка была подтверждена в XP, Vista и Windows 7.

Непечатаемые символы и опция /P
Опция /P заставляет FINDSTR пропускать любой файл, который содержит любой из следующих десятичных байтовых кодов:
0-7, 14-25, 27-31.

Другими словами, опция /P будет пропускать только те файлы, которые содержат непечатные управляющие символы. Управляющие символы - это коды, которые меньше или равны 31 (0x1F). FINDSTR рассматривает следующие управляющие символы как печатные:

 8  0x08  backspace
 9  0x09  horizontal tab
10  0x0A  line feed
11  0x0B  vertical tab
12  0x0C  form feed
13  0x0D  carriage return
26  0x1A  substitute (end of text)

Все остальные управляющие символы обрабатываются как непечатные, наличие которых приводит к пропуску файла опцией /P.

Канальный и перенаправленный ввод может иметь добавленный <CR><LF>
Если ввод передается по каналу и последний символ потока не является <LF>, то FINDSTR автоматически добавит <CR><LF> к входу. Это было подтверждено в XP, Vista и Windows 7. (Раньше я думал, что канал Windows был ответственен за изменение ввода, но с тех пор я обнаружил, что FINDSTR фактически делает изменение.)

То же самое верно для перенаправленного ввода в Vista. Если последний символ файла, используемого в качестве перенаправленного ввода, не является <LF>, то FINDSTR автоматически добавит <CR><LF> к вводу. Однако XP и Windows 7 не изменяют перенаправленный ввод.

FINDSTR зависает на XP и Windows 7, если перенаправленный ввод не заканчивается на <LF>
Это неприятная "функция" в XP и Windows 7. Если последний символ файла, используемого в качестве перенаправленного ввода, не заканчивается на <LF>, то FINDSTR будет зависать бесконечно, как только достигнет конца перенаправленного файла.

Последняя строка данных Piped может быть проигнорирована, если она состоит из одного символа
Если ввод введен и последняя строка состоит из одного символа, за которым не следует <LF>, тогда FINDSTR полностью игнорирует последнюю строку.

Пример. Первая команда с одним символом и без <LF> не может соответствовать, но вторая команда с 2 символами работает нормально, как и третья команда с одним символом с завершающим переводом строки.

> set /p "=x" <nul | findstr "^"

> set /p "=xx" <nul | findstr "^"
xx

> echo x| findstr "^"
x

Об этом сообщил пользователь DosTips Спанч Белли из новой ошибки findstr. Подтверждено на XP, Windows 7 и Windows 8. Еще не слышал о Vista. (У меня больше нет Vista для тестирования).

Синтаксис опций
Для параметров можно добавить префикс / или - Опции могут быть объединены после одного / или -. Однако объединенный список параметров может содержать не более одного параметра с несколькими символами, например OFF или F:, а параметр из нескольких символов должен быть последним параметром в списке.

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

  • /i /r /c:"hello.*goodbye" /c:"goodbye.*hello"

  • -i -r -c:"hello.*goodbye" /c:"goodbye.*hello"

  • /irc:"hello.*goodbye" /c:"goodbye.*hello"

Ограничения длины строки поиска
В Vista максимально допустимая длина одной строки поиска составляет 511 байт. Если какая-либо строка поиска превышает 511, результатом будет ошибка FINDSTR: Search string too long. с ошибкой ERRORLEVEL 2.

При выполнении поиска по регулярному выражению максимальная длина строки поиска составляет 254. Регулярное выражение с длиной от 255 до 511 приведет к ошибке FINDSTR: Out of memory с ошибкой ERRORLEVEL 2. Длина регулярного выражения> 511 приведет к ошибке FINDSTR: Search string too long..

В Windows XP длина строки поиска явно меньше. Ошибка Findstr: "слишком длинная строка поиска": как извлечь и сопоставить подстроку в цикле "for"? Ограничение XP составляет 127 байтов для литеральных и регулярных поисков.

Пределы длины линии
Файлы, указанные в качестве аргумента командной строки или с помощью параметра /F: FILE, не имеют известного ограничения длины строки. Поиск был успешно выполнен для файла размером 128 МБ, в котором не было ни одного тега & lt; LF>.

Данные по конвейеру и перенаправленный ввод ограничены 8191 байтами на строку. Этот лимит является "особенностью" FINDSTR. Это не присуще pipeм или перенаправлению. FINDSTR, использующий перенаправленный ввод stdin или piped, никогда не будет соответствовать ни одной строке размером> = 8 Кбайт. Строки> = 8k генерируют сообщение об ошибке для stderr, но значение ERRORLEVEL равно 0, если строка поиска найдена хотя бы в одной строке хотя бы одного файла.

Тип поиска по умолчанию: буквальное или регулярное выражение
/C:"string" - По умолчанию используется значение /L. Явное объединение параметра /L с/C: "строка", безусловно, работает, но является избыточным.

"string argument" - Значение по умолчанию зависит от содержимого самой первой строки поиска. (Помните, что & lt; пробел> используется для разделения строк поиска.) Если первая строка поиска является допустимым регулярным выражением, которое содержит хотя бы один неэкранированный метасимвол, то все строки поиска обрабатываются как регулярные выражения. В противном случае все строки поиска рассматриваются как литералы. Например, "51.4 200" будет обрабатываться как два регулярных выражения, потому что первая строка содержит неэкранированную точку, тогда как "200 51.4" будет обрабатываться как два литерала, поскольку первая строка не содержит метасимволов.

/G:file - Значение по умолчанию зависит от содержимого первой непустой строки в файле. Если первая строка поиска является допустимым регулярным выражением, которое содержит хотя бы один неэкранированный метасимвол, то все строки поиска обрабатываются как регулярные выражения. В противном случае все строки поиска рассматриваются как литералы.

Рекомендация - всегда явно указывайте опцию /L литерала или опцию регулярного выражения /R при использовании "string argument" или /G:file.

ОШИБКА. Задание нескольких литеральных строк поиска может привести к ненадежным результатам

В следующем простом примере FINDSTR не удается найти совпадение, хотя оно и должно быть.

echo ffffaaa|findstr /l "ffffaaa faffaffddd"

Эта ошибка была подтверждена в Windows Server 2003, Windows XP, Vista и Windows 7.

Основываясь на экспериментах, FINDSTR может потерпеть неудачу, если выполнены все следующие условия:

  • В поиске используются несколько буквенных строк поиска
  • Строки поиска имеют разную длину
  • Короткая строка поиска имеет некоторое перекрытие с более длинной строкой поиска
  • В поиске учитывается регистр (без опции /I)

При каждом сбое, которое я видел, всегда происходит сбой одной из более коротких строк поиска.

Для получения дополнительной информации см. Почему этот пример FINDSTR с несколькими строковыми поисковыми строками не находит соответствия?

Кавычки и обратные слова в аргументах командной строки
Примечание. Комментарии пользователя MC ND отражают действительно ужасно сложные правила для этого раздела. Существует 3 этапа анализа:

  • Первый cmd.exe может потребовать экранирования некоторых кавычек как ^ "(на самом деле ничего общего с FINDSTR)
  • Далее FINDSTR использует анализатор аргументов до 2008 MS C/C++, который имеет специальные правила для "и \
  • После завершения синтаксического анализа аргумента FINDSTR дополнительно обрабатывает \, сопровождаемый буквенно-цифровым символом, как литерал, но\сопровождаемый не буквенно-цифровым символом, как escape-символ

Остальная часть этого выделенного раздела не на 100% правильна. Он может служить руководством для многих ситуаций, но приведенные выше правила необходимы для полного понимания.

Экранирование кавычек в строках поиска командной строки
Кавычки в строках поиска командной строки должны быть экранированы с помощью обратной косой черты \". Это верно как для литеральных, так и для регулярных поисковых строк. Этот информация была подтверждена в XP, Vista и Windows 7.

Примечание. Может также потребоваться экранирование кавычки для синтаксического анализатора CMD.EXE, но это не имеет ничего общего с FINDSTR. Например, чтобы найти одиночная кавычка, которую вы можете использовать:

FINDSTR \^" file && echo found || echo not found

Экранирование обратной косой черты в командной строке литеральных строк поиска
Обратная косая черта в литеральной строке поиска обычно может быть представлена как \ или как \\. Они, как правило, эквивалентны. (Там может быть необычно случаи в Vista, где всегда следует избегать обратной косой черты, но я нет больше есть машина Vista для тестирования).

Но есть несколько особых случаев:

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

  • \\ может быть закодирован как \\\ или \\\\
  • \\\ может быть закодирован как \\\\\ или \\\\\\

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

  • \" должен быть закодирован как \\\\\"
  • \\" должен быть закодирован как \\\\\\\\\"

Как отмечалось ранее, одна или несколько экранированных кавычек могут также потребовать экранирования с ^ для синтаксического анализатора CMD

Информация в этом разделе была подтверждена на XP и Windows 7.

Экранирование обратной косой черты в строке поиска регулярных выражений в командной строке

  • Только для Vista: Обратная косая черта в регулярном выражении должна быть либо экранирована двойным образом, как \\\\, либо экранирована одиночным экранированием в наборе классов символов, например [\\]

  • XP и Windows 7: Обратная косая черта в регулярном выражении всегда может быть представлена как [\\]. Обычно он может быть представлен как \\. Но это никогда работает, если обратная косая черта предшествует экранированной кавычке.

    Одна или несколько обратных косых черт перед экранированной кавычкой должны быть двойное экранирование или кодирование как [\\]

    • \" может быть закодирован как \\\\\" или [\\]\"
    • \\" может быть закодирован как \\\\\\\\\" или [\\][\\]\" или \\[\\]\"

Экранирование кавычек и обратной косой черты в /G: FILE строковые строки поиска
Автономные кавычки и обратные косые черты в файле с литеральной строкой поиска, указанной в /G: не нужно экранировать, но они могут быть.

" и \" эквивалентны.

\ и \\ эквивалентны.

Если цель состоит в том, чтобы найти \\, то, по крайней мере, должен быть экранирован начальный обратный слеш. Оба \\\ и \\\\ работают.

Если цель состоит в том, чтобы найти \", то, по крайней мере, должен быть экранирован начальный обратный слеш. Оба \\" и \\\" работают.

Экранирование кавычек и обратной косой черты в строках /G: FILE regex
Это единственный случай, когда escape-последовательности работают, как и ожидалось, основываясь на документации. Цитата не является метасимволом регулярных выражений, поэтому ее не нужно экранировать (но можно). Обратная косая черта является метасимволом регулярных выражений, поэтому ее необходимо экранировать.

Пределы символов для параметров командной строки - Расширенное преобразование ASCII
Нулевой символ (0x00) не может появляться ни в одной строке командной строки. Любой другой однобайтовый символ может появиться в строке (0x01 - 0xFF). Однако FINDSTR преобразует многие расширенные символы ASCII, которые он находит в параметрах командной строки, в другие символы. Это оказывает серьезное влияние двумя способами:

1) Многие расширенные символы ASCII не будут совпадать, если они используются в качестве строки поиска в командной строке. Это ограничение одинаково для литеральных и регулярных поисков. Если строка поиска должна содержать расширенный ASCII, вместо этого следует использовать опцию /G:FILE.

2) FINDSTR может не найти файл, если имя содержит расширенные символы ASCII и имя файла указано в командной строке. Если файл для поиска содержит расширенный ASCII в имени, тогда вместо него следует использовать опцию /F:FILE.

Вот полный список расширенных преобразований символов ASCII, которые FINDSTR выполняет в строках командной строки. Каждый символ представлен в виде десятичного значения байтового кода. Первый код представляет символ, указанный в командной строке, а второй код представляет символ, в который он преобразован. Обратите внимание - этот список был составлен на компьютере в США. Я не знаю, какое влияние на этот список могут оказать другие языки.

158 treated as 080     199 treated as 221     226 treated as 071
169 treated as 170     200 treated as 043     227 treated as 112
176 treated as 221     201 treated as 043     228 treated as 083
177 treated as 221     202 treated as 045     229 treated as 115
178 treated as 221     203 treated as 045     231 treated as 116
179 treated as 221     204 treated as 221     232 treated as 070
180 treated as 221     205 treated as 045     233 treated as 084
181 treated as 221     206 treated as 043     234 treated as 079
182 treated as 221     207 treated as 045     235 treated as 100
183 treated as 043     208 treated as 045     236 treated as 056
184 treated as 043     209 treated as 045     237 treated as 102
185 treated as 221     210 treated as 045     238 treated as 101
186 treated as 221     211 treated as 043     239 treated as 110
187 treated as 043     212 treated as 043     240 treated as 061
188 treated as 043     213 treated as 043     242 treated as 061
189 treated as 043     214 treated as 043     243 treated as 061
190 treated as 043     215 treated as 043     244 treated as 040
191 treated as 043     216 treated as 043     245 treated as 041
192 treated as 043     217 treated as 043     247 treated as 126
193 treated as 045     218 treated as 043     249 treated as 250
194 treated as 045     219 treated as 221     251 treated as 118
195 treated as 043     220 treated as 095     252 treated as 110
196 treated as 045     222 treated as 221     254 treated as 221
197 treated as 043     223 treated as 095
198 treated as 221     224 treated as 097

Любой символ> 0, отсутствующий в приведенном выше списке, рассматривается как сам по себе, включая <CR> и & lt; LF>. Самый простой способ включить нечетные символы, такие как <CR> и <LF>, - поместить их в переменную окружения и использовать отложенное расширение в аргументе командной строки.

Пределы символов для строк, найденных в файлах, указанных в параметрах /G: FILE и /F: FILE
Символ nul (0x00) может появиться в файле, но он действует как терминатор строки C. Любые символы после нулевого символа обрабатываются как другая строка, как если бы они были в другой строке.

Символы <CR> и <LF> обрабатываются как ограничители строки, которые заканчивают строку и не включаются в строку.

Все остальные однобайтовые символы полностью включены в строку.

Поиск файлов Unicode
FINDSTR не может правильно искать большинство Unicode (UTF-16, UTF-16LE, UTF-16BE, UTF-32), потому что он не может искать нулевые байты, а Unicode обычно содержит много нулевых байтов.

Однако команда TYPE преобразует UTF-16LE с BOM в однобайтовый набор символов, поэтому такая команда будет работать с UTF-16LE с BOM.

type unicode.txt|findstr "search"

Обратите внимание, что кодовые точки Unicode, которые не поддерживаются вашей активной кодовой страницей, будут преобразованы в символы ?.

Поиск в UTF-8 возможен, если строка поиска содержит только ASCII. Однако вывод на консоль любых многобайтовых символов UTF-8 будет неправильным. Но если вы перенаправите вывод в файл, то результат будет правильно закодирован UTF-8. Обратите внимание, что если файл UTF-8 содержит спецификацию, эта спецификация будет считаться частью первой строки, что может привести к сбою в поиске, который соответствует началу строки.

Можно искать многобайтовые символы UTF-8, если поместить строку поиска в файл поиска в кодировке UTF-8 (без спецификации) и использовать параметр /G.

Конец строки
FINDSTR разрывает строки сразу после каждого & lt; LF>. Наличие или отсутствие & lt; CR> не влияет на разрывы строк.

Поиск через разрывы строк
Как и ожидалось, метасимвол регулярного выражения . не будет совпадать с & lt; CR> или & lt; LF>. Но можно искать через разрыв строки, используя строку поиска командной строки. Символы & lt; CR> и & lt; LF> должны совпадать явно. Если найдено многострочное совпадение, печатается только 1-я строка совпадения. Затем FINDSTR удваивается до 2-ой строки в источнике и снова начинает поиск - что-то вроде функции "смотреть вперед".

Предположим, что TEXT.TXT содержит это содержимое (может быть в стиле Unix или Windows)

A
A
A
B
A
A

Тогда этот сценарий

@echo off
setlocal
::Define LF variable containing a linefeed (0x0A)
set LF=^


::Above 2 blank lines are critical - do not remove

::Define CR variable containing a carriage return (0x0D)
for /f %%a in ('copy /Z "%~dpf0" nul') do set "CR=%%a"

setlocal enableDelayedExpansion
::regex "!CR!*!LF!" will match both Unix and Windows style End-Of-Line
findstr /n /r /c:"A!CR!*!LF!A" TEST.TXT

дает эти результаты

1:A
2:A
5:A

Поиск по разрывам строк с использованием параметра /G: FILE является неточным, поскольку единственный способ сопоставить & lt; CR> или & lt; LF> - это выражение диапазона классов символов регулярных выражений, которое помещает символы EOL.

  • [<TAB>-<0x0B>] соответствует & lt; LF>, но также соответствует & lt; TAB> и & lt; 0x0B>

  • [<0x0C>-!] соответствует & lt; CR>, но также соответствует & lt; 0x0C> и!

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

Ответ продолжен в части 2 ниже...

Ответ 2

Ответ продолжен из части 1 выше - я столкнулся с лимитом ответа 30 000 символов: - (

Ограниченные регулярные выражения (регулярное выражение) Поддержка
Поддержка FINDSTR для регулярных выражений крайне ограничена. Если это не в документации HELP, оно не поддерживается.

Кроме того, поддерживаемые выражения регулярного выражения реализуются совершенно нестандартным образом, так что результаты могут быть разными, поэтому можно ожидать, что результаты будут получены от чего-то вроде grep или perl.

Ярлыки позиции регулярных выражений ^ и $
^ соответствует началу входного потока, а также любой позиции, непосредственно следующей за <LF> . Поскольку FINDSTR также разбивает строки после <LF> , простое регулярное выражение "^" всегда будет соответствовать всем строкам в файле, даже двоичному файлу.

$ соответствует любой позиции, непосредственно предшествующей <CR> . Это означает, что строка поиска регулярных выражений, содержащая $, никогда не будет соответствовать строкам в текстовом файле стиля Unix и не будет соответствовать последней строке текстового файла Windows, если отсутствует маркер EOL в <CR> <LF> .

Примечание. Как обсуждалось ранее, при подключении и перенаправлении ввода к FINDSTR может быть добавлено <CR><LF>, которое не находится в источнике. Очевидно, это может повлиять на поиск регулярных выражений, в котором используется $.

Любая строка поиска с символами до ^ или после $ всегда будет не в состоянии найти соответствие.

Позиционные параметры /B/E/X
Позиционные параметры работают так же, как ^ и $, за исключением того, что они также работают для строк литералов.

/B действует так же, как ^ в начале строки поиска в регулярном выражении.

/E действует так же, как $ в конце строки поиска регулярных выражений.

/X работает так же, как и ^ в начале и $ в конце строки поиска регулярных выражений.

граница слова Regex
\< должен быть самым первым членом в регулярном выражении. Регулярное выражение не будет соответствовать ни одному другому, если ему предшествуют другие символы. \< соответствует либо самому началу ввода, началу строки (позиция, непосредственно следуя за <LF> ), либо положению, непосредственно следующему за символом "не-слово". Следующий символ не обязательно должен быть "словом".

\> должен быть самым последним членом в регулярном выражении. Регулярное выражение не будет соответствовать ни одному другому, если за ним последуют другие символы. \> соответствует либо концу ввода, либо позиции непосредственно перед символом <CR> , либо позиции, непосредственно предшествующей любому символу "без слова". Предыдущий символ не обязательно должен быть "словом".

Вот полный список символов "не-слов", представленных в виде десятичного байтового кода. Примечание. Этот список был скомпилирован на машине U.S. Я не знаю, какое влияние могут иметь другие языки в этом списке.

001   028   063   179   204   230
002   029   064   180   205   231
003   030   091   181   206   232
004   031   092   182   207   233
005   032   093   183   208   234
006   033   094   184   209   235
007   034   096   185   210   236
008   035   123   186   211   237
009   036   124   187   212   238
011   037   125   188   213   239
012   038   126   189   214   240
014   039   127   190   215   241
015   040   155   191   216   242
016   041   156   192   217   243
017   042   157   193   218   244
018   043   158   194   219   245
019   044   168   195   220   246
020   045   169   196   221   247
021   046   170   197   222   248
022   047   173   198   223   249
023   058   174   199   224   250
024   059   175   200   226   251
025   060   176   201   227   254
026   061   177   202   228   255
027   062   178   203   229

Диапазоны классов символов регулярных выражений [x-y]
Диапазоны классов символов не работают должным образом. См. Этот вопрос: Почему findstr не обрабатывает регистр должным образом (в некоторых случаях)? вместе с этим ответом: fooobar.com/questions/28775/....

Проблема заключается в том, что FINDSTR не сопоставляет символы по их байтовому значению (обычно считается кодом ASCII, но ASCII определяется только с 0x00 - 0x7F). Большинство реализаций регулярных выражений рассматривали бы [A-Z] как все заглавные буквы верхнего регистра английского языка. Но FINDSTR использует последовательность сортировки, которая примерно соответствует тому, как работает SORT. Таким образом, [A-Z] включает полный английский алфавит, как верхний, так и нижний регистр (кроме "a" ), а также неанглийские альфа-символы с диакритическими знаками.

Ниже приведен полный список всех символов, поддерживаемых FINDSTR, отсортированных в последовательности сортировки, используемой FINDSTR для установки диапазонов классов символов регулярных выражений. Символы представляются в виде значения их десятичного байтового кода. Я считаю, что последовательность сортировки имеет наибольший смысл, если символы просматриваются с использованием кодовой страницы 437. Примечание. Этот список был скомпилирован на машине U.S. Я не знаю, какое влияние могут иметь другие языки в этом списке.

001
002
003
004
005
006
007
008
014
015
016
017
018           
019
020
021
022
023
024
025
026
027
028
029
030
031
127
039
045
032
255
009
010
011
012
013
033
034
035
036
037
038
040
041
042
044
046
047
058
059
063
064
091
092
093
094
095
096
123
124
125
126
173
168
155
156
157
158
043
249
060
061
062
241
174
175
246
251
239
247
240
243
242
169
244
245
254
196
205
179
186
218
213
214
201
191
184
183
187
192
212
211
200
217
190
189
188
195
198
199
204
180
181
182
185
194
209
210
203
193
207
208
202
197
216
215
206
223
220
221
222
219
176
177
178
170
248
230
250
048
172
171
049
050
253
051
052
053
054
055
056
057
236
097
065
166
160
133
131
132
142
134
143
145
146
098
066
099
067
135
128
100
068
101
069
130
144
138
136
137
102
070
159
103
071
104
072
105
073
161
141
140
139
106
074
107
075
108
076
109
077
110
252
078
164
165
111
079
167
162
149
147
148
153
112
080
113
081
114
082
115
083
225
116
084
117
085
163
151
150
129
154
118
086
119
087
120
088
121
089
152
122
090
224
226
235
238
233
227
229
228
231
237
232
234

Лимит сроков символа символа регулярного выражения и BUG
Мало того, что FINDSTR ограничивается максимум 15 символами в регулярном выражении, он не может правильно обработать попытку превысить лимит. Использование 16 или более терминов класса символов приводит к появлению интерактивного всплывающего окна Windows, в котором говорится, что утилита "Найти строку (QGREP) столкнулась с проблемой и должна закрыть. Мы сожалеем о неудобствах". Текст сообщения немного меняется в зависимости от версии Windows. Вот один пример FINDSTR, который завершится неудачно:

echo 01234567890123456|findstr [0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]

Эта ошибка была зарегистрирована пользователем DosTips Judago здесь. Это было подтверждено на XP, Vista и Windows 7.

Поиск в Regex не выполняется (и может вешать бесконечно), если они включают байтовый код 0xFF (decimal 255)
Любой поиск регулярных выражений, который включает в себя байтовый код 0xFF (decimal 255), не будет выполнен. Он не работает, если байтовый код 0xFF включен напрямую или если он неявно включен в диапазон классов символов. Помните, что диапазоны классов символов FINDSTR не группируют символы на основе значения байтового кода. Символ <0xFF> появляется относительно рано в последовательности сортировки между символами <space> и <tab>. Поэтому любой диапазон классов символов, который включает в себя как <space>, так и <tab>, не будет выполнен.

Точное поведение немного меняется в зависимости от версии Windows. Windows 7 зависает бесконечно, если включен 0xFF. XP не зависает, но всегда не удается найти совпадение и иногда выводит следующее сообщение об ошибке - "Процесс пытался записать в несуществующий канал".

У меня больше нет доступа к машине Vista, поэтому я не смог протестировать ее в Vista.

Ошибка регулярного выражения: . и [^anySet] может соответствовать End-of-File
Метасимвол регулярного выражения . должен соответствовать только любому символу, отличному от <CR> или <LF>. Существует ошибка, которая позволяет ему сопоставлять End-Of-File, если последняя строка в файле не завершена <CR> или <LF>. Однако . не будет содержать пустой файл.

Например, файл с именем "test.txt", содержащий одну строку x, без завершения <CR> или <LF>, будет соответствовать следующему:

findstr /r x......... test.txt

Эта ошибка была подтверждена на XP и Win7.

То же самое верно для отрицательных наборов символов. Что-то вроде [^abc] будет соответствовать End-of-File. Положительные наборы символов, такие как [abc], как представляется, работают нормально. Я тестировал это только на Win7.

Ответ 3

findstr иногда неожиданно зависает при поиске больших файлов.

Я не подтвердил точные условия или размеры границ. Я подозреваю, что любой файл размером более 2 ГБ может оказаться под угрозой.

У меня был смешанный опыт с этим, поэтому это больше, чем просто размер файла. Похоже, что это может быть вариант FINDSTR зависает на XP и Windows 7, если перенаправленный ввод не заканчивается LF, но, как показано, эта конкретная проблема проявляется, когда ввод не.

Следующий сеанс командной строки (Windows 7) демонстрирует, как findstr может зависать при поиске 3GB файла.

C:\Data\Temp\2014-04>echo 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890> T100B.txt

C:\Data\Temp\2014-04>for /L %i in (1,1,10) do @type T100B.txt >> T1KB.txt

C:\Data\Temp\2014-04>for /L %i in (1,1,1000) do @type T1KB.txt >> T1MB.txt

C:\Data\Temp\2014-04>for /L %i in (1,1,1000) do @type T1MB.txt >> T1GB.txt

C:\Data\Temp\2014-04>echo find this line>> T1GB.txt

C:\Data\Temp\2014-04>copy T1GB.txt + T1GB.txt + T1GB.txt T3GB.txt
T1GB.txt
T1GB.txt
T1GB.txt
        1 file(s) copied.

C:\Data\Temp\2014-04>dir
 Volume in drive C has no label.
 Volume Serial Number is D2B2-FFDF

 Directory of C:\Data\Temp\2014-04

2014/04/08  04:28 PM    <DIR>          .
2014/04/08  04:28 PM    <DIR>          ..
2014/04/08  04:22 PM               102 T100B.txt
2014/04/08  04:28 PM     1 020 000 016 T1GB.txt
2014/04/08  04:23 PM             1 020 T1KB.txt
2014/04/08  04:23 PM         1 020 000 T1MB.txt
2014/04/08  04:29 PM     3 060 000 049 T3GB.txt
               5 File(s)  4 081 021 187 bytes
               2 Dir(s)  51 881 050 112 bytes free
C:\Data\Temp\2014-04>rem Findstr on the 1GB file does not hang

C:\Data\Temp\2014-04>findstr "this" T1GB.txt
find this line

C:\Data\Temp\2014-04>rem On the 3GB file, findstr hangs and must be aborted... even though it clearly reaches end of file

C:\Data\Temp\2014-04>findstr "this" T3GB.txt
find this line
find this line
find this line
^C
C:\Data\Temp\2014-04>

Примечание. Я проверил в шестнадцатеричном редакторе, что все строки завершены с помощью CRLF. Единственная аномалия в том, что файл заканчивается 0x1A из-за способ copy работает. Обратите внимание, однако, что эта аномалия не вызывает проблемы с "маленькими" файлами.

При дополнительном тестировании я подтвердил следующее:

  • Использование copy с опцией /b для двоичных файлов предотвращает добавление символа 0x1A, а findstr не зависает в файле 3GB.
  • Завершение работы 3GB файла с другим символом также приводит к зависанию findstr.
  • Символ 0x1A не вызывает никаких проблем в "маленьком" файле. (Аналогично для других завершающих символов.)
  • Добавление CRLF после 0x1A устраняет проблему. (LF сам по себе, вероятно, будет достаточным.)
  • Использование type для соединения файла с файлом findstr работает без зависания. (Это может быть связано с побочным эффектом либо type, либо |, который вставляет дополнительный End Of Line.)
  • Использовать перенаправленный вход < также приводит к зависанию findstr. Но это ожидается; как описано в dbenham post: "перенаправленный вход должен заканчиваться на LF".

Ответ 4

Когда несколько команд заключены в круглые скобки и перенаправлены файлы на весь блок:

< input.txt (
   command1
   command2
   . . .
) > output.txt

... тогда файлы остаются открытыми, пока активны команды в блоке, поэтому команды могут перемещать указатель файла перенаправленных файлов. Команды MORE и FIND перемещают указатель файла Stdin в начало файла перед его обработкой, поэтому один и тот же файл может обрабатываться несколько раз внутри блока. Например, этот код:

more < input.txt >  output.txt
more < input.txt >> output.txt

... производит тот же результат, что и этот:

< input.txt (
   more
   more
) > output.txt

Этот код:

find    "search string" < input.txt > matchedLines.txt
find /V "search string" < input.txt > unmatchedLines.txt

... производит тот же результат, что и этот:

< input.txt (
   find    "search string" > matchedLines.txt
   find /V "search string" > unmatchedLines.txt
)

FINDSTR отличается; он не перемещает указатель файла Stdin из текущей позиции. Например, этот код вставляет новую строку после строки поиска:

call :ProcessFile < input.txt
goto :EOF

:ProcessFile
   rem Read the next line from Stdin and copy it
   set /P line=
   echo %line%
   rem Test if it is the search line
   if "%line%" neq "search line" goto ProcessFile
rem Insert the new line at this point
echo New line
rem And copy the rest of lines
findstr "^"
exit /B

Мы можем эффективно использовать эту функцию с помощью вспомогательной программы, которая позволяет нам перемещать указатель файла перенаправленного файла, как показано в этом примере.

Такое поведение было впервые сообщено jeb на этом посту.


EDIT 2018-08-18: Сообщена новая ошибка FINDSTR

Команда FINDSTR имеет странную ошибку, которая возникает, когда эта команда используется для отображения символов в цвете И вывод такой команды перенаправляется на устройство CON. Подробнее о том, как использовать команду FINDSTR для отображения текста в цвете, см. В этом разделе.

Когда вывод этой формы команды FINDSTR перенаправляется в CON, что-то странное происходит после того, как текст выводится в желаемом цвете: весь текст после его вывода как "невидимые" символы, хотя более точное описание состоит в том, что текст вывод черного текста на черном фоне. Исходный текст появится, если вы используете команду COLOR для сброса цветов переднего плана и фона всего экрана. Однако, когда текст "невидим", мы можем выполнить команду SET/P, поэтому все введенные символы не будут отображаться на экране. Это поведение можно использовать для ввода паролей.

@echo off
setlocal

set /P "=_" < NUL > "Enter password"
findstr /A:1E /V "^$" "Enter password" NUL > CON
del "Enter password"
set /P "password="
cls
color 07
echo The password read is: "%password%"

Ответ 5

Я хочу сообщить об ошибке в разделе Источник данных для поиска в первом ответе при использовании en dash (-) или em dash (-) в имени файла.

В частности, если вы собираетесь использовать первый вариант - имена файлов, указанные в качестве аргументов, файл не будет найден. Как только вы используете вариант 2 - stdin через перенаправление или 3 - поток данных из канала, findstr найдет файл.

Например, эта простая партия script:

echo off
chcp 1250 > nul
set INTEXTFILE1=filename with – dash.txt
set INTEXTFILE2=filename with — dash.txt

rem 3 way of findstr use with en dashed filename
echo.
echo Filename with en dash:
echo.
echo 1. As argument
findstr . "%INTEXTFILE1%"
echo.
echo 2. As stdin via redirection
findstr . < "%INTEXTFILE1%"
echo.
echo 3. As datastream from a pipe
type "%INTEXTFILE1%" | findstr .
echo.
echo.
rem The same set of operations with em dashed filename
echo Filename with em dash:
echo.
echo 1. As argument
findstr . "%INTEXTFILE2%"
echo.
echo 2. As stdin via redirection
findstr . < "%INTEXTFILE2%"
echo.
echo 3. As datastream from a pipe
type "%INTEXTFILE2%" | findstr .
echo.

pause

напечатает:

Имя файла с помощью en dash:

  • Как аргумент FINDSTR: невозможно открыть имя файла с помощью - dash.txt

  • Как stdin через перенаправление
    Я - файл с en dash.

  • Как поток данных от трубы Я - файл с en dash.

Имя файла с типом em:

  • Как аргумент FINDSTR: невозможно открыть имя файла с помощью - dash.txt

  • Как stdin через перенаправление
    Я - файл с типом em.

  • Как поток данных от трубы Я - файл с типом em.

Надеюсь, что это поможет.

М.

Ответ 6

Команда findstr устанавливает ErrorLevel (или код выхода) на одно из следующих значений, учитывая, что нет недопустимых или несовместимых переключателей и ни одна строка поиска не превышает применимые ограничение длины:

  • 0 когда встречается хотя бы одно совпадение в одной строке во всех указанных файлах;
  • 1 в противном случае;

Считается, что строка содержит совпадение, когда:

  • опция /V не указана, и поисковое выражение встречается хотя бы один раз;
  • указана опция /V, а поисковое выражение не встречается;

Это означает, что опция /V также изменяет возвращенный ErrorLevel, но он не просто возвращает его!

Например, когда у вас есть файл test.txt с двумя строками, одна из которых содержит строку text, а другая - нет, и findstr "text" "test.txt", и findstr /V "text" "test.txt" возвращают ErrorLevel из 0.

По сути, вы можете сказать: если findstr возвращает хотя бы строку, для ErrorLevel устанавливается значение 0, в противном случае - для 1.

Обратите внимание, что опция /M не влияет на значение ErrorLevel, она просто изменяет вывод.

(Для полноты картины: команда find ведет себя точно так же по отношению к опциям /V и ErrorLevel; опция /C не влияет на ErrorLevel.)

Ответ 7

/D для нескольких каталогов: поместите список каталогов перед строкой поиска. Все эти работы:

findstr /D:dir1;dir2 "searchString" *.*
findstr /D:"dir1;dir2" "searchString" *.*
findstr /D:"\path\dir1\;\path\dir2\" "searchString" *.*

Как и ожидалось, путь относится к местоположению, если вы не запускаете каталоги с помощью \. Окружение пути с помощью " является необязательным, если в именах каталогов нет пробелов. Окончание \ не является обязательным. Вывод местоположения будет включать в себя любой путь, который вы ему даете. Он будет работать с окружением каталога или без него с помощью ".