Jak wydrukować zawartość pliku tylko wtedy, gdy pierwszy wiersz pasuje do określonego wzorca?

11

Piszę skrypt, chcę sprawdzić, czy pierwszy wiersz pliku pasuje do określonego wzorca, a jeśli tak, to wydrukuj plik. Jak mogę to osiągnąć?

Jak mogę sprawdzić wzór? Czy istnieje sposób na sprawdzenie wzoru i na podstawie danych wyjściowych zrób coś…

EDYCJA: Proszę spojrzeć na to pytanie: /programming/5536018/how-to-get-match-regex-pattern-using-awk-from-file

Chcę czegoś takiego, ale żaden z nich nie działał dla mnie. Zasadniczo chcę sprawdzić, czy pierwszy wiersz pasuje do wzorca wyrażenia regularnego, czy nie i na podstawie tego wydrukować wiersze pliku.

Mathew
źródło
1
Jakiej wydajności oczekujesz? Jakiego wzoru szukasz? Czego spróbowałeś do tej pory?
tachomi
@tachomi edytowane, proszę spojrzeć
Mathew

Odpowiedzi:

17

Możesz to zrobić za pomocą ed:

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

sztuczka polega na tym, aby spróbować zastąpić się PATTERNon- 1stline. edwyskoczy z błędu, jeśli nie może znaleźć określonego wzorca, więc ,p(wydrukuj cały plik) zostanie wykonany, tylko jeśli 1s/PATTERN/&/się powiedzie.

Lub z sed:

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

to quits jeśli pierwsza linia nie ( !) odpowiadają PATTERN, inaczej prints wszystkie linie.
Lub, jak wskazał Toby Speight , z GNU sed:

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

Qjest taki sam jak, qale nie drukuje przestrzeni wzoru.

don_crissti
źródło
Możesz Qzamiast qGNU sed lub dwcześniej q(przenośny), aby nie wymagać odpowiednio -nflagi i ppolecenia: sed '1{/PATTERN/!Q}' infilelub sed -e '1{' -e '/PATTERN/!{' -e 'd' -e 'q' -e '}' -e '}' infile, odpowiednio.
Toby Speight
dponownie uruchamia cykl poleceń, który zawsze mnie łapie! : - |
Toby Speight
W GNU sedpierwsze sedpolecenie narzeka sed: -e expression #1, char 10: extra characters after command(z powodu p), ale edostatnie sedsugestie działają dobrze.
Skippy le Grand Gourou,
Uwaga: Rozwiązania przedstawione w tej odpowiedzi mają tę zaletę, że w porównaniu z innymi odpowiedziami można je zastosować na rurze.
Skippy le Grand Gourou,
1
@SkippyleGrandGourou - próbowałeś zamienić go w jednowierszowy bez oddzielania poleceń średnikami - jest to właściwy sposób, aby to zrobićsed -n '1{/PATTERN/!q};p'
don_crissti
15

Z skrzynią z narzędziami POSIX:

{ head -n 1 | grep pattern && cat; } <file
Cuonglm
źródło
1
{double} <słodki.
mikeserv
@mikeserv: Mam zamiar użyć go, aby zapobiec myleniu nowej osoby, ale edytowany Stephane jest bardziej przejrzysty.
cuonglm
8
 awk '/pattern/{print FILENAME}; {nextfile}' ./*.txt

by wydrukować nazwę non-ukryte txtpliki w bieżącym katalogu, którego pierwsza linia pasuje rozszerzonego wyrażenia regularnego patternz tych awkinplementations że wsparcienextfile .

Jeśli zamiast wydrukować nazwę pliku, chcesz wydrukować całą zawartość pliku, możesz:

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

Jest to wydajne, ponieważ uruchamia tylko jedno polecenie, ale awknie jest najskuteczniejszym poleceniem zrzutu zawartości pliku, w przypadku dużych plików można uzyskać lepszą wydajność, wykonując coś takiego:

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

Oznacza to, że należy awkgo używać tylko do drukowania listy pasujących plików (rozdzielonych cyfrą 0) i polegać na catzrzutach ich zawartości.

Stéphane Chazelas
źródło
6

Jeśli piszesz skrypt powłoki, możesz coś takiego

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

Lub w Perlu:

perl -Tlne '$f = /PATTERN/ if $. == 1; print if $f; $. = 0 if eof' ./*
terdon
źródło
@ Stéphane Chazelas: Może close ARGVto bardziej idiom niż przypisywanie $..
cuonglm
@terdon Twój wygląda jak kod golfowy, wszystko w jednym wierszu, bez nawiasów wokół nazw zmiennych i nie zachęca do czystej struktury. A kiedy pisałem, brakowało ci znaku dolara, to po prostu nie sposób uczyć bash. Zakładam, że te czynniki pochodzą z tła Perla, które również wydajesz się mieć, więc zostanie ci wybaczone! ;)
@guest witaj na stronie! Przekształciłem twoją odpowiedź w komentarz, ponieważ odpowiedzi powinny być zamieszczane tylko wtedy, gdy odpowiadają na rzeczywiste pytanie. To nie jest forum w klasycznym sensie i chcemy tutaj tylko czystych pytań i odpowiedzi. Możesz zajrzeć do centrum pomocy lub wybrać się na wycieczkę, aby lepiej zrozumieć witrynę. To powiedziawszy, moje tło jest w biologii, więc tak, mój kod jest daleki od czystości :) Jednak nie widzę, jak nawiasy pomogłyby tutaj, cytaty już chronią zmienną. Co by to złamało, przed którym chroniłyby się nawiasy?
terdon
@ gość Ach, przepraszam, zapomniałem, że nie możesz komentować. Zapraszam do przyjścia i wyjaśnienia na czacie , jestem pewien, że mogę się czegoś nauczyć.
terdon
5

Oldschool, po prostu przetłumacz swoje zdanie na standardowe polecenia:

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

Nauka bash to dobry początek. Jeśli potrzebujesz tylko szybkiego rozwiązania, wypróbuj odpowiedzi sed-, awk- lub perl. Oba są ładne, ale są to własne języki, których potrzebujesz (i prawdopodobnie chcesz) się uczyć.

Jest to dość prosty przykład, więc jeśli chcesz dowiedzieć się więcej, możesz spróbować tego samego w Ruby, PHP, Js (np. W Nodejs) lub w innym języku, który pozwala na dostęp do plików. Nawet C / C ++ lub Java powinny być łatwe do zarządzania przy niewielkim zadaniu.

Gość
źródło
1
Jest to w zasadzie to samo co moje, z wyjątkiem tego, że używasz if/elsezamiast [ ] &&.
terdon