У меня есть куча файлов, и я хочу найти, какой из них содержит последовательные строки, начинающиеся с определенной строки.
Например, для следующего файла:
Aaaaaaaaaaaa
Baaaaaaaaaaa
Cxxxxxxxxx
Cyyyyyyyyy
Czzzzzzzzz
Abbbbbbbbbbb
Bbbbbbbbbbbb
Caaaaaa
Accccccccccc
Bccccccccccc
Cdddddd
Ceeeeee
Существует более одной строки, начинающейся с 'C', поэтому я хочу, чтобы этот файл находился по команде.
Например, для следующего файла:
Aaaaaaaaaaaa
Baaaaaaaaaaa
Cxxxxxxxxx
Abbbbbbbbbbb
Bbbbbbbbbbbb
Caaaaaa
Accccccccccc
Bccccccccccc
Cdddddd
Всегда есть одна строка, начинающаяся с 'C', я не хочу этот файл. Я думал об использовании grep
или, sed
но я не знаю точно, как это сделать. Может быть, с помощью регулярного выражения ^C.*$^C
или что-то в этом роде. Есть идеи ?
C
втором примере начинаются две строки .C
?grep
версий.Ответы:
С
pcregrep
:POSIXly:
(хотя это означает полное чтение всех файлов с теми
awk
реализациями, которые не поддерживаютnextfile
).С версиями GNU
grep
до 2.5.4:кажется, что работает, но это случайно, и это не гарантировано, чтобы работать.
Прежде, чем это было исправлено в 2.6 (с помощью этого коммита ), GNU
grep
упустила из виду, что используемая им функция поиска pcre будет соответствовать всему буферу, обрабатываемому в данный моментgrep
, вызывая все виды неожиданного поведения. Например:будет соответствовать на файле, содержащем:
Это будет соответствовать:
Но это:
Или:
не будет (так как
1\n2\n
обрабатывается через два буфераgrep
).Это поведение в итоге было задокументировано, хотя:
После того, как это было исправлено в 2.6, документация не была изменена (я однажды сообщил об этом там ).
источник
exit
и-exec \;
вместо nextfile?awk
на файл. Вы захотите сделать это только в том случае, если ваш файлawk
не поддерживает,nextfile
и у вас есть большая часть файлов, которые имеют большой размер и совпадают с линиями в начале файла.-z
с-P
. Там нет\N
без-P
, вы должны были бы написать ее ,$'[\01-\011\013-\0377]'
которая будет работать только в локалей C (см thread.gmane.org/gmane.comp.gnu.grep.bugs/5187 )С
awk
:Это напечатает содержимое файла, если есть последовательные строки, начинающиеся с
C
. Выражение(p ~ /^C/ && $1 ~ /^C/)
будет смотреть на последовательные строки в файле и будет иметь значение true, если первый символ в обоих совпаденияхC
. Если это так, строка будет напечатана.Чтобы найти все файлы с таким шаблоном, вы можете запустить приведенный выше awk с помощью
find
команды:В этой команде
find
+exec
будет проходить через каждый из файлов и выполнять аналогичнуюawk
фильтрацию для каждого файла и печатать его имя,FILENAME
если выражение awk оценивается как true. Чтобы не печататьFILENAME
несколько раз для одного файла с несколькими совпадениями, используетсяexit
оператор (спасибо @terdon).источник
C
flag
, простоexit
вместо этого. Таким образом, вам не нужно продолжать обработку файлов после того, как совпадение было найдено.Еще один вариант с GNU
sed
:Для одного файла:
(хотя он также сообщит о файлах, которые он не может прочитать).
Для
find
:Проблемы с нечитаемыми файлами при печати можно избежать, написав это:
источник
sed -n '$q1;/^C/{n;/^C/q}'
?$q1
- вынуждает sed завершиться с ошибкой, если шаблон не найден. Он также завершится с ошибкой, если что-то не так с файлом (он не читается или поврежден). Таким образом, он выйдет с нулевым статусом выхода только в том случае, если шаблон найден и будет передан на печать. Расстаться с/^C/{n;/^C/q
довольно просто. Если он находит строку, которая начинается с C, он будет читать следующую строку, а если он также начинается с C, он выйдет с нулевым статусом выхода.Предполагая, что ваши файлы достаточно малы для чтения в память:
Объяснение:
000
: установить\n\n
в качестве разделителя записей, это включает режим абзаца, который будет обрабатывать абзацы (разделенные последовательными символами новой строки) как отдельные строки.-ne
: применить скрипт, указанный в качестве аргумента, к-e
каждой строке входного файла (ов).$ARGV
: файл обрабатывается в данный момент/^C[^\n]*\nC/
: совпадениеC
в начале строки (см. описаниеsm
модификаторов ниже, чтобы узнать, почему это работает здесь), за которым следуют 0 или более символов, не являющихся символом новой строки, символ новой строки и затем еще один C. Другими словами, найдите последовательные строки, начинающиеся сC
. *//sm
: эти модификаторы соответствия (как описано [здесь]):Вы также можете сделать что-то ужасное, как:
Здесь
perl
код заменяет символы новой строки на%%
so, так что, если у вас нет%%
входного файла ( если, конечно, большого ), ониgrep
будут соответствовать последовательным строкам, начинающимся сC
.источник
РЕШЕНИЕ:
DEMO:
Сначала мы создадим тестовую базу:
Выше создается 26 файлов в
/tmp
именованныхfile1-26
. В каждом файле 27 или 28 строк, начинающихся с буквa-z
и сопровождаемых остальной частью алфавита. Каждый третий файл содержит две последовательные строки, в которых дублируется первый символ.ОБРАЗЕЦ:
И когда я меняюсь:
чтобы:
Я получил...
ВЫВОД:
Итак, вкратце, решение работает так:
источник
Этот скрипт использует
grep
иcut
для получения номеров строк совпадающих строк и проверяет любые два последовательных номера. Предполагается, что файл является допустимым именем файла, переданным в качестве первого аргумента скрипту:источник