Как распечатать содержимое файла, только если первая строка соответствует определенному шаблону?

11

Я пишу сценарий, я хочу проверить, соответствует ли первая строка файла определенному шаблону, и если это так, распечатать файл. Как мне этого добиться?

Как проверить шаблон? Есть ли способ проверить шаблон и на основе вывода сделать что-нибудь ..

РЕДАКТИРОВАТЬ: Пожалуйста, посмотрите на этот вопрос: /programming/5536018/how-to-get-match-regex-pattern-using-awk-from-file

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

Mathew
источник
1
Какой выход вы ожидаете? Какой шаблон вы ищете? что ты уже испробовал?
Тачоми
@tachomi отредактировал, пожалуйста, посмотрите
Мэтью

Ответы:

17

Вы можете сделать это с ed:

ed -s infile <<\IN 2>/dev/null
1s/PATTERN/&/
,p
q
IN

Хитрость заключается в том, чтобы попытаться заменить PATTERNна 1stсебя. edвыдает ошибку, если не может найти указанный шаблон, поэтому ,p(распечатать весь файл) будет выполнен только в случае 1s/PATTERN/&/успеха.

Или с sed:

sed -n '1{
/PATTERN/!q
}
p' infile

он qиспользуется, если первая строка не !совпадает ( ) PATTERN, иначе он pпечатает все строки.
Или, как указал Тоби Спейт , с GNU sed:

sed '1{/PATTERN/!Q}' infile

Qто же самое, qно не печатает пространство шаблона.

don_crissti
источник
Вы можете Qвместо qGNU sed или dbefore q(переносимый), чтобы не требовать -nфлаг и pкоманду: sed '1{/PATTERN/!Q}' infileили sed -e '1{' -e '/PATTERN/!{' -e 'd' -e 'q' -e '}' -e '}' infile, соответственно.
Тоби Спейт
dперезапускает командный цикл, который всегда ловит меня! : - |
Тоби Спейт
С GNU sedпервая sedкоманда жалуется sed: -e expression #1, char 10: extra characters after command(из-за p), но edи последние sedпредложения работают нормально.
Скиппи ле Гран Гуру
NB. Решения, представленные в этом ответе, имеют преимущество перед другими ответами в том, что их можно применять на трубе.
Скиппи ле Гран Гуру
1
@SkippyleGrandGourou - вы пытались превратить его в однострочник, не разделяя команды точками с запятой - это правильный способ сделать этоsed -n '1{/PATTERN/!q};p'
don_crissti
15

Сундук с инструментами POSIX:

{ head -n 1 | grep pattern && cat; } <file
cuonglm
источник
1
{двойной} <сладкий.
mikeserv
@mikeserv: я намереваюсь использовать его, чтобы не запутать нового человека, но отредактированный Стефан понятнее.
Cuonglm
8
 awk '/pattern/{print FILENAME}; {nextfile}' ./*.txt

напечатает имя не скрытых txtфайлов в текущем каталоге, первая строка которого соответствует расширенному регулярному выражению patternс теми awkподдержаниями, которые поддерживаютnextfile .

Если вместо печати имени файла вы хотите напечатать содержимое всего файла, вы можете сделать:

 awk 'FNR == 1 && ! /pattern/ {nextfile}; {print}' ./*.txt

Это эффективно в том смысле, что он запускает только одну команду, но, awkбудучи не самой эффективной командой для выгрузки содержимого файла с большими файлами, вы могли бы добиться лучшей производительности, выполнив что-то вроде:

 awk '/pattern/{printf "%s\0", FILENAME}; {nextfile}' ./*.txt |
   xargs -r0 cat

То есть используйте только awkдля печати списка файлов, которые совпадают (с разделителями 0) и используют catдля выгрузки своего содержимого.

Стефан Шазелас
источник
6

Если вы пишете сценарий оболочки, вы могли бы что-то вроде

for file in ./*; do head -n 1 "$file" | grep -q 'PATTERN' && cat "$file"; done

Или в Perl:

perl -Tlne '$f = /PATTERN/ if $. == 1; print if $f; $. = 0 if eof' ./*
Тердон
источник
@ Стефан Шазелас: Может быть, close ARGVэто больше идиома, чем назначение $..
Cuonglm
@terdon Yours выглядит как code golf, все в одной строке, без скобок вокруг имен переменных и не способствует чистой структуре. И у меня был пропавший знак доллара, когда я писал, это просто не способ учить Баш. Я предполагаю, что эти факторы проистекают из того, что у вас также есть в Perl, так что вы будете прощены! ;)
@guest привет и добро пожаловать на сайт! Я преобразовал ваш ответ в комментарий, поскольку ответы следует размещать только в том случае, если они отвечают на конкретный вопрос. Это не форум в классическом смысле, и мы хотим только чистые вопросы и ответы здесь. Возможно, вы захотите взглянуть на справочный центр или совершить экскурсию, чтобы лучше понять сайт. Тем не менее, мой опыт на самом деле в биологии, так что да, мой код далеко не чистый :) Однако я не вижу, как скобки помогли бы здесь, кавычки уже защищают переменную. Что бы сломать это, от которого будут защищены скобки?
Тердон
@ гость ах, извините, забыл, что вы не можете комментировать. Не стесняйтесь приходить и объяснять в чате , я уверен, что могу чему-то научиться.
Тердон
5

Oldschool, просто переведите предложение в стандартные команды:

for file in *; do
    if head -n 1 "${file}" | grep -q 'PATTERN'; then
        cat "${file}"
    fi
done

Для изучения Bash это хорошее начало. Если вам просто нужно быстрое решение, попробуйте sed-, awk- или perl-ответы. Оба хороши, но это собственные языки, которые вы должны (и, вероятно, хотите) выучить.

Это довольно простой пример, поэтому, если вы хотите узнать больше, вы можете попробовать то же самое в ruby, php, js (например, в nodejs) или любом другом языке, который разрешает доступ к файлам. Даже C / C ++ или Java должны легко управляться с небольшой задачей.

гость
источник
1
Это в основном так же, как у меня, за исключением того, что вы используете if/elseвместо [ ] &&.
Terdon