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


11

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

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

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

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


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но не печатает пространство шаблона.


Вы можете 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

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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.