Come troncare le linee di corrispondenza lunghe restituite da grep o ack


91

Voglio eseguire ack o grep su file HTML che spesso hanno righe molto lunghe. Non voglio vedere righe molto lunghe che vanno a capo ripetutamente. Ma voglio vedere solo quella parte di una lunga linea che circonda una stringa che corrisponde all'espressione regolare. Come posso ottenerlo utilizzando qualsiasi combinazione di strumenti Unix?


1
Cosa ack? È un comando che usi quando non ti piace qualcosa? Qualcosa di simile ack file_with_long_lines | grep pattern? :-)
Alok Singhal

6
@Alok ack(noto come ack-grepsu Debian) è grepsotto steroidi. Ha anche l' --thppptopzione (non sto scherzando). betterthangrep.com
ZoogieZork

Grazie. Ho imparato qualcosa oggi.
Alok Singhal

1
Mentre la --thppptfunzione è alquanto controversa, il vantaggio chiave sembra essere che è possibile utilizzare Perl regex direttamente, non qualche pazzo [[:space:]]e personaggi come {, [ecc cambiando cioè con l' -ee -Einterruttori in un modo che è impossibile da ricordare.
Evgeni Sergeev

Risposte:


101

Potresti usare l'opzione grep -o, possibilmente in combinazione con la modifica del tuo modello ".{0,10}<original pattern>.{0,10}"in per vedere un contesto attorno ad esso:

       -o, --only-matching
              Mostra solo la parte di una linea corrispondente che corrisponde a PATTERN.

..oppure -c:

       -c, --count
              Sopprime l'output normale; stampa invece un conteggio delle righe corrispondenti
              per ogni file di input. Con l'opzione -v, --invert-match (vedi
              sotto), conta le righe non corrispondenti.

44
un esempio: grep -oE ". {0,20} mysearchstring. {0,20}" myfile
Renaud

14
dovresti cambiare la risposta per aggiungere l'opzione -E come mostrato da @Renaud (opzione modello esteso), altrimenti il ​​modello proposto per estendere il contesto non funzionerà.
kriss

Forse non è necessario, ma ecco un esempio: $ echo "eeeeeeeeeeeeeeeeeeeeqqqqqqqqqqqqqqqqqqqqMYSTRINGwwwwwwwwwwwwwwwwwwwwrrrrrrrrrrrrrrrrrrrrr" > fileonelongline.txt && grep -oE ".{0,20}MYSTRING.{0,20}" ./fileonelongline.txt stampeqqqqqqqqqqqqqqqqqqqqMYSTRINGwwwwwwwwwwwwwwwwwwww
Ulises Layera

1
Funziona bene; ma uno svantaggio notevole è che quando si usa, ad esempio, oE ".{0,20}mysearchstring.{0,20}"si perde l'evidenziazione della stringa "originale" interna rispetto al contesto, perché l'intera cosa diventa il modello di ricerca. Mi piacerebbe trovare un modo per mantenere un contesto non evidenziato attorno ai risultati della ricerca, per una scansione visiva e un'interpretazione dei risultati molto più semplici.
Aaron Wallentine,

1
Oh, ecco una soluzione al problema di evidenziazione causato dall'utilizzo -oE ".{0,x}foo.{0,x}"dell'approccio (dov'è xil numero di caratteri del contesto) - append `| grep foo `fino alla fine. Funziona per soluzioni ack o grep. Altre soluzioni anche qui: unix.stackexchange.com/questions/163726/…
Aaron Wallentine

45

Trasmetti i tuoi risultati cut. Sto anche valutando l'aggiunta di un --cutinterruttore in modo da poter dire --cut=80e ottenere solo 80 colonne.


8
E se la parte che corrisponde non è nei primi 80 caratteri?
Ether

3
FWIW ho aggiunto | cut=c1-120al grep, ha funzionato per me (anche se non so come tagliare il testo abbinato)
Jake Rayson

26
| cut=c1-120non ha funzionato per me, dovevo farlo| cut -c1-120
Ken Cochrane

1
Penso che @edib sia accurato nella sintassi | cut -c 1-100 stackoverflow.com/a/48954102/1815624
CrandellWS

1
@ AndyLester: che ne dici di --no-wrapun'opzione che utilizza $COLUMNS?
nought101

25

Puoi usare less come cercapersone per ack and chop long lines: ack --pager="less -S" questo mantiene la linea lunga ma la lascia su una linea invece di andare a capo. Per vedere più della riga, scorrere a sinistra / destra in meno con i tasti freccia.

Ho la seguente configurazione alias per ack per fare questo:

alias ick='ack -i --pager="less -R -S"' 

2
Nota che puoi mettere quel --pagercomando nel tuo file ~ / .ackrc, se vuoi usarlo sempre.
Andy Lester

Sembra di gran lunga la migliore soluzione a questo problema che mi infastidisce molto. Vorrei saperlo usare ack.
Brian Peterson

@BrianPeterson ackè più o meno come grep, solo più semplice nei casi più comuni
Aaron Wallentine

8
cut -c 1-100

ottiene caratteri da 1 a 100.


2

Tratto da: http://www.topbug.net/blog/2016/08/18/truncate-long-matching-lines-of-grep-a-solution-that-preserves-color/

L'approccio suggerito ".{0,10}<original pattern>.{0,10}"è perfettamente buono tranne per il fatto che il colore dell'evidenziazione è spesso incasinato. Ho creato uno script con un output simile ma anche il colore è preservato:

#!/bin/bash

# Usage:
#   grepl PATTERN [FILE]

# how many characters around the searching keyword should be shown?
context_length=10

# What is the length of the control character for the color before and after the
# matching string?
# This is mostly determined by the environmental variable GREP_COLORS.
control_length_before=$(($(echo a | grep --color=always a | cut -d a -f '1' | wc -c)-1))
control_length_after=$(($(echo a | grep --color=always a | cut -d a -f '2' | wc -c)-1))

grep -E --color=always "$1" $2 |
grep --color=none -oE \
    ".{0,$(($control_length_before + $context_length))}$1.{0,$(($control_length_after + $context_length))}"

Supponendo che lo script sia salvato come grepl, allora grepl pattern file_with_long_linesdovrebbe visualizzare le righe corrispondenti ma con solo 10 caratteri intorno alla stringa corrispondente.


Funziona, ma restituisce spazzatura finale per me, in questo modo: ^ [[? 62; 9; c. Non ho provato a eseguire il debug perché la risposta di @Jonah Braun mi ha soddisfatto.
sondra.kinsey

2

inserisci qui la descrizione dell'immagine

Nella situazione insolita in cui non puoi usare -E, puoi usare:

grep -oe ".\{0,10\}error.\{0,10\}" mylogfile.txt

1

Ecco cosa faccio:

function grep () {
  tput rmam;
  command grep "$@";
  tput smam;
}

Nel mio .bash_profile, sovrascrivo grep in modo che venga eseguito automaticamente tput rmamprima e tput smamdopo, il che disabilita il wrapping e quindi lo riattiva.


Questa è una bella alternativa - tranne se la partita effettiva è quindi fuori dallo schermo ...
Xerus

0

Ho inserito quanto segue nel mio .bashrc:

grepl() {
    $(which grep) --color=always $@ | less -RS
}

È quindi possibile utilizzare greplsulla riga di comando con qualsiasi argomento disponibile per grep. Usa i tasti freccia per vedere la coda delle linee più lunghe. Usa qper smettere.

Spiegazione:

  • grepl() {: Definisci una nuova funzione che sarà disponibile in ogni (nuova) console bash.
  • $(which grep): Ottieni il percorso completo di grep. (Ubuntu definisce un alias per grepquesto è equivalente a grep --color=auto. Non vogliamo quell'alias ma l'originale grep.)
  • --color=always: Consente di colorare l'output. ( --color=autodall'alias non funzionerà poiché greprileva che l'output viene inserito in una pipe e non lo colorerà quindi.)
  • $@: Inserisce qui tutti gli argomenti forniti alla greplfunzione.
  • less: Visualizza le linee usando less
  • -R: Mostra i colori
  • S: Non rompere le linee lunghe
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.