Come stampare il contenuto del file solo se la prima riga corrisponde a un determinato modello?


11

Sto scrivendo uno script, voglio verificare se la prima riga del file corrisponde a un determinato modello e se lo stampa quindi il file. Come posso raggiungere questo obiettivo?

Come posso verificare il motivo? C'è un modo per verificare il modello e in base all'output fare qualcosa ..

MODIFICA: Dai un'occhiata a questa domanda: /programming/5536018/how-to-get-match-regex-pattern-using-awk-from-file

Voglio qualcosa del genere, ma nessuno di loro ha funzionato per me. Fondamentalmente voglio verificare se la prima riga corrisponde o meno a un modello regex e in base a quello stampa le righe del file.


1
Qual è l'output che ti aspetti? Qual è lo schema che stai cercando? Cosa hai provato fino ad ora?
Tachomi,

@tachomi modificato per favore dai un'occhiata
Mathew,

Risposte:


17

Puoi farlo con ed:

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

il trucco qui è provare a sostituire PATTERNin 1stlinea con se stesso. edsbaglierà se non riesce a trovare il modello specificato, quindi ,p(stampa l'intero file) verrà eseguito solo se ha 1s/PATTERN/&/esito positivo.

O con sed:

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

questo qvale se la prima riga non corrisponde ( !) PATTERN, altrimenti pstampa tutte le righe.
O, come sottolineato da Toby Speight , con GNU sed:

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

Qè uguale a qma non stampa lo spazio del motivo.


È possibile Qinvece che qper GNU sed, o dprima q(portatile) in modo da non richiedere il -nflag e il pcomando: sed '1{/PATTERN/!Q}' infileo sed -e '1{' -e '/PATTERN/!{' -e 'd' -e 'q' -e '}' -e '}' infile, rispettivamente.
Toby Speight,

driavvia il ciclo di comando che mi sorprende sempre! : - |
Toby Speight,

Con GNU sedil primo sedcomando si lamenta sed: -e expression #1, char 10: extra characters after command(a causa del p), ma gli edultimi sedsuggerimenti funzionano bene.
Skippy le Grand Gourou,

NB: Le soluzioni fornite da questa risposta hanno il merito, rispetto ad altre risposte, che possono essere applicate su una pipe.
Skippy le Grand Gourou,

1
@SkippyleGrandGourou - hai provato a trasformarlo in una riga senza separare i comandi con punto e virgola - questo è il modo corretto di farlosed -n '1{/PATTERN/!q};p'
don_crissti

15

Con la cassa degli strumenti POSIX:

{ head -n 1 | grep pattern && cat; } <file

1
{double} <dolce.
Mikeserv,

@mikeserv: ho intenzione di usarlo per evitare che nuove persone confondano, ma Stephane modificato è più chiaro.
cuonglm,

8
 awk '/pattern/{print FILENAME}; {nextfile}' ./*.txt

stampa il nome dei txtfile non nascosti nella directory corrente la cui prima riga corrisponde all'espressione regolare estesa patterncon quelle awkimplementazioni che supportanonextfile .

Se invece di stampare il nome del file, vuoi stampare l'intero contenuto del file, puoi fare:

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

È efficiente in quanto esegue solo un comando, ma awknon essendo il comando più efficiente per scaricare il contenuto di un file, con file di grandi dimensioni, potresti ottenere prestazioni migliori facendo qualcosa del tipo:

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

Cioè, utilizzare solo awkper stampare l'elenco dei file corrispondenti (delimitati da 0) e fare affidamento catper scaricare il loro contenuto.


6

Se stai scrivendo uno script di shell, potresti fare qualcosa del genere

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

Oppure, in Perl:

perl -Tlne '$f = /PATTERN/ if $. == 1; print if $f; $. = 0 if eof' ./*

@ Stéphane Chazelas: Forse close ARGVè più idioma che assegnarlo $..
cuonglm,

@terdon Yours sembra un codice golf, tutto in una riga, senza parentesi attorno ai nomi delle variabili e non incoraggia una struttura pulita. E avevi un simbolo del dollaro mancante quando ho pubblicato, non è questo il modo di insegnare a Bash. Presumo che quei fattori provengano dallo sfondo del perl che sembra che tu abbia, quindi sarai perdonato! ;)

@guest ciao e benvenuto nel sito! Ho convertito la tua risposta in un commento poiché le risposte dovrebbero essere pubblicate solo se stanno rispondendo alla domanda reale. Questo non è un forum in senso classico e qui vogliamo solo domande e risposte. Potresti dare un'occhiata al centro assistenza o fare il tour per capire meglio il sito. Detto questo, il mio background è in realtà in biologia, quindi sì, il mio codice è tutt'altro che pulito :) Tuttavia, non vedo come le parentesi possano aiutare qui, le virgolette proteggono già la variabile. Cosa romperebbe ciò da cui proteggerebbero le parentesi?
terdon

@guest ah, scusa, ho dimenticato che non puoi commentare. Sentiti libero di venire e spiegare in chat , sono sicuro che potrei imparare qualcosa.
terdon

5

Oldschool, basta tradurre la frase in comandi standard:

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

Per imparare bash è un buon inizio. Se hai solo bisogno di una soluzione rapida, prova le risposte sed, awk o perl. Entrambi simpatici, ma sono le tue lingue che devi (e probabilmente vuoi) imparare.

È un esempio piuttosto semplice, quindi se vuoi saperne di più, puoi anche provare lo stesso in ruby, php, js (ad esempio in nodejs) o in qualsiasi altra lingua che consenta l'accesso ai file. Anche C / C ++ o Java dovrebbero essere facili da gestire con un piccolo compito.


1
Questo è fondamentalmente uguale al mio, tranne che si utilizza al if/elseposto di [ ] &&.
terdon
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.