Come grep le righe che hanno un certo valore in una colonna specifica?


9

Ho un file come il seguente

  200.000    1.353    0.086
  200.250    1.417    0.000
  200.500    1.359    0.091
  200.750    1.423    0.000
  201.000    1.365    0.093
  201.250    1.427    0.000
  201.500    1.373    0.093
  201.750    1.432    0.000
  202.000    1.383    0.091
  202.250    1.435    0.000
  202.500    1.392    0.087
  202.750    1.436    0.000
  203.000    1.402    0.081
  203.250    1.437    0.001
  203.500    1.412    0.073
  204.000    1.423    0.065
  204.500    1.432    0.055
  205.000    1.441    0.045  

Vorrei grep solo le righe che hanno nella prima colonna i decimali .000 e .500 solo così l'output sarebbe così

  200.000    1.353    0.086
  200.500    1.359    0.091
  201.000    1.365    0.093
  201.500    1.373    0.093
  202.000    1.383    0.091
  202.500    1.392    0.087
  203.000    1.402    0.081
  203.500    1.412    0.073
  204.000    1.423    0.065
  204.500    1.432    0.055
  205.000    1.441    0.045  

2
Sembra abbastanza facile. Cosa hai provato fino ad ora? Quali problemi ha avuto il tuo codice?
Giovanni 1024,

forse è facile per te ma ho provato con grep '.000' | grep '.005' ma ordina anche le righe che hanno lo stesso valore in altre colonne
Mohsen El-Tahawy,

3
Molto bene. Le persone qui sono molto più simpatiche se mostri un onesto tentativo di risolvere il problema da solo. Il codice nel tuo commento lo dimostra. In futuro, se includi tentativi del genere nella tua domanda, probabilmente otterrai risposte migliori più velocemente.
Giovanni 1024,

Risposte:


14

Non usi grep. Usa awk.

"your data" | awk '$1 ~ /\.[05]00/'

Molto bene. Come scritto, il codice dipende dal fatto che ci sono esattamente tre cifre dopo il decimale. Sarebbe più robusto da usare awk '$1 ~ /\.[05]0*$/'.
Giovanni 1024

1
@ John1024, in realtà come scritto il codice dipende dal fatto che ci siano almeno tre cifre dopo il decimale. Inclinerei awk '$1 ~ /\.[05]00$/'me stesso (richiedo esattamente tre cifre), a meno che non avessi motivo di pensare che nell'input siano previsti decimali variabili.
Carattere jolly

2
@Wildcard Se ce ne sono più di tre, il codice potrebbe non riuscire. Ad esempio: echo 0.5001 | awk '$1 ~ /\.[05]00/'. Funziona in modo affidabile solo se ce ne sono esattamente tre.
Giovanni 1024,

4
awk '$1 ~ /\.[50]00/ { print $0 }' myFile.txt

La prima colonna $1verrà confrontata con /\.500|\.000/i punti sfuggiti per essere punti letterali non regex alcun carattere la ~corrispondenza parziale e stampare l'intera riga$0


2
Nessun motivo per includere { print $0 }; questa è l'azione predefinita di Awk.
Carattere jolly

4

Vorrei grep solo le righe che hanno nella prima colonna i decimali .000 e .500

Il mio primo pensiero

grep '^ *[0-9][0-9][0-9]\.[50]00' filename

Test rapido tramite WSL

$ head testdata
              200.000    1.353    0.086
              200.250    1.417    0.000
              200.500    1.359    0.091
              200.750    1.423    0.000
              201.000    1.365    0.093
              201.250    1.427    0.000
              201.500    1.373    0.093
              201.750    1.432    0.000
              202.000    1.383    0.091
              202.250    1.435    0.000
$ grep '^ *[0-9][0-9][0-9]\.[50]00' testdata
              200.000    1.353    0.086
              200.500    1.359    0.091
              201.000    1.365    0.093
              201.500    1.373    0.093
              202.000    1.383    0.091
              202.500    1.392    0.087
              203.000    1.402    0.081
              203.500    1.412    0.073
              204.000    1.423    0.065
              204.500    1.432    0.055
              205.000    1.441    0.045

Ci sono modi più concisi per esprimere questo.

$ grep -E '^ *[0-9]{3}\.[50]00' testdata
              200.000    1.353    0.086
              200.500    1.359    0.091
              201.000    1.365    0.093
              201.500    1.373    0.093
              202.000    1.383    0.091
              202.500    1.392    0.087
              203.000    1.402    0.081
              203.500    1.412    0.073
              204.000    1.423    0.065
              204.500    1.432    0.055
              205.000    1.441    0.045

Se la prima colonna può avere una parte intera diversa da 3 cifre

grep -E '^ *[0-9]+\.[05]00' testdata

In alcune circostanze potrebbe essere necessario utilizzare [:digit:]al posto di [0-9].

E così via.

man grep È tuo amico.


Questo uso di grepè più facile da usare del mio. Non avrei pubblicato una risposta se l'avessi vista prima. Bel lavoro!
Yokai

2

A seconda del caso d'uso, è possibile utilizzare anche operazioni numeriche effettive:

$ awk '{a = $1 % 1} a == 0 || a == 0.5' /tmp/foo
  200.000    1.353    0.086
  200.500    1.359    0.091
  201.000    1.365    0.093
  201.500    1.373    0.093
  202.000    1.383    0.091
  202.500    1.392    0.087
  203.000    1.402    0.081
  203.500    1.412    0.073
  204.000    1.423    0.065
  204.500    1.432    0.055
  205.000    1.441    0.045

Testato con BSD awk (OSX El Capitan, 20070501) e GNU awk 4.1.4.


1
Avvertenza: testare l'uguaglianza esatta del virgola mobile (che utilizza awk) spesso dà risultati "errati" a meno che i valori non abbiano una parte frazionaria (e non siano di grandezza troppo grande), o la parte frazionaria sia "binaria" (esattamente la metà, un quarto, ecc.) che è vero per i dati in questo Q ma non molti altri che sembrano simili ai non iniziati.
dave_thompson_085,

1
@ dave_thompson_085 in effetti, ma con gawk puoi usare l'aritmetica di precisione arbitraria , è vero che non li sto usando qui.
muru,


2

Con awk:

$>awk '$1%.5==0' data.tsv 
200.000 1.353   0.086
200.500 1.359   0.091
201.000 1.365   0.093
201.500 1.373   0.093
202.000 1.383   0.091
202.500 1.392   0.087
203.000 1.402   0.081
203.500 1.412   0.073
204.000 1.423   0.065
204.500 1.432   0.055
205.000 1.441   0.045

Con mlr:

$>mlr --ifs tab --onidx filter '$1%.5==0' data.tsv 
200.000 1.353 0.086
200.500 1.359 0.091
201.000 1.365 0.093
201.500 1.373 0.093
202.000 1.383 0.091
202.500 1.392 0.087
203.000 1.402 0.081
203.500 1.412 0.073
204.000 1.423 0.065
204.500 1.432 0.055
205.000 1.441 0.045

2

Ok, aggiungo un po 'tardi al mio contributo, ma penso che ne valga la pena.

Il requisito da soddisfare, per l'OP è la prima colonna con il valore decimale .000o .500solo. Non è previsto il valore guida, per intervallo o lunghezza. Per robustezza, non si deve presumere che sia vincolato da nulla tranne che non ci sono caratteri non vuoti prima della prima colonna (o non è più la prima colonna) e che il contenuto della prima colonna avrà un punto decimale ., in esso da qualche parte.

L'OP vuole usare grep, che stamperà l'intera riga quando viene trovata una corrispondenza, quindi l'unica cosa da fare è creare il modello che corrisponda a tutto e solo ciò che è richiesto.

Semplicità stessa, e nessun motivo per usare sedo awkcome `grep può gestire il sorgente come file o pipe.

Per grepun file utilizzaregrep '^[^.]*\.[05]0\{2\}\s' the_file.txt

Da grepuna pipa, usaremy_command | grep '^[^.]*\.[05]0\{2\}\s'

Il modello è:, ^inizia all'inizio della riga; [^.], abbina qualsiasi carattere non decimale; *, il maggior numero di volte possibile (incluso nessuno); \., abbina un punto decimale; [05], abbina un cinque o uno zero; 0\{2\}, abbina altri 2 zeri (le barre rovesciate prima della parentesi aperta e chiusa impediscono alla shell di tentare di eseguire l'espansione della parentesi); \s, abbina un carattere di spazio (che indica la fine della colonna - da utilizzare in un caso d'uso diverso, sostituiscilo con il separatore di colonna, in genere un segno comune, un punto e virgola o una scheda \t).

Si noti che questo corrisponderà esattamente a ciò che l'OP ha chiesto. Essa non corrispondere .5000o .0000anche se numericamente equivalente, perché l'aspetto del modello per cinque o zero, seguiti da esattamente 2 più zeri seguiti da spazi bianchi. Se questo è significativo, allora tutte le altre risposte, finora, falliscono in quanto corrisponderanno a qualsiasi numero di zeri, maggiore di 1, dopo la cifra del test. E ad eccezione della risposta di FloHimself, corrisponderanno a qualsiasi cosa nella seconda colonna che inizia .000 o .500, incluso .0003e .500T, e quella di FloHimself corrisponderà a qualsiasi cosa matematicamente equivalente a .0e.5, non importa quanti zeri ci siano. L'ultimo, pur non corrispondendo a quanto dichiarato dall'OP, probabilmente corrisponderà a ciò di cui l'OP ha bisogno comunque.

Infine, se awksi desidera la potenza e la velocità di , anche se l'OP ha richiesto grep, il comando sarebbe:

Con un file awk '$1 ~ /[^.]\.[05]0{2}$/' the_file.txt

Con una pipa my_command | awk '$1 ~ /[^.]\.[05]0{2}$/'


1

Se insisti nell'usare grep, questo potrebbe funzionare per te. Ho salvato il primo output fornito in un file di testo chiamato "file.txt" e quindi ho utilizzato il comando seguente:

grep -e '2[^ ]*.000' file.txt & grep -e '2[^ ]*.500' file.txt

Che dà un output di:

200.000    1.353    0.086
200.500    1.359    0.091
201.500    1.373    0.093
201.000    1.365    0.093
202.500    1.392    0.087
202.000    1.383    0.091
203.500    1.412    0.073
203.000    1.402    0.081
204.500    1.432    0.055
204.000    1.423    0.065
205.000    1.441    0.045

Non dovrai salvare l'output in un file di testo se è già in un file. Ma nel caso in cui non venga salvato in un file, puoi anche reindirizzare i dati nel comando grep che ho fornito e dovrebbe funzionare almeno fino al primo numero 2, nella prima colonna non è più un 2. A quel punto dovrai aggiornare il comando grep con il carattere appropriato per stampare correttamente.

Ciò che sta accadendo con questo doppio grepcomando è che il primo grepviene inviato in background con l' &operatore. Quando viene inviato in background, il grepcomando successivo viene eseguito immediatamente dopo, fornendo un output uniforme. Affinché l'attività che devi completare sia eseguita più facilmente, dovresti seguire l'esempio che altri hanno dato e utilizzato awko addirittura sed.

(modificare)

Questo non è affatto l'uso migliore o più efficace di grep per le tue esigenze, ma dovrebbe essere sufficiente per giocare un po 'e avere una migliore sensazione di grep.


Il primo processo viene eseguito in background, ma non demone che include l' esecuzione in background, ma un po 'di più. Ed è molto improbabile che produca output nello stesso ordine dell'input; anche nel tuo esempio piuttosto piccolo è già andato storto nella terza riga.
dave_thompson_085,

Non menziona che l'output deve essere in un ordine specifico. Solo che deve essere specifico per .500e .000della prima colonna. Se è necessario che si trovi in ​​un ordine specifico, come dal minimo al massimo, ciò può essere fatto facilmente. Tuttavia, le prime 3 cifre delle prime colonne stampate sono almeno al massimo ordine. Questo è il risultato di 2[^ ]*.000e 2[^ ]*.500. È abbastanza adatto a ciò che l'OP ha chiesto.
Yokai

Nota anche la mia modifica per il disclaimer sull'efficienza per il comando che ho fornito.
Yokai
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.