awk sed if statement


9

Sto cercando di aggiungere 0 all'inizio, SE c'è un "." al 2 ° carattere di quella riga. Non riuscivo a combinare questi due;

awk '{ print substr( $0, 2, 1 ) }' file.txt 

mostrando il secondo personaggio

sed -ie "s/.\{0\}/0/" file.txt

aggiungendo uno zero all'inizio.

Dovrebbe esserci un "se il secondo carattere è un punto".

file di esempio:

1.02.2017 23:40:00
10.02.2017 23:40:00

finale:

01.02.2017 23:40:00
10.02.2017 23:40:00

Risposte:


12

È possibile utilizzare sedo awkper risolvere completamente il problema.


Con sed:

$ sed 's/^.\./0&/' file.txt

Quando si &verifica nella parte sostitutiva del comando di sostituzione ( s), verrà espansa nella parte della riga di input che corrisponde alla parte del modello del comando.

L'espressione regolare ^.\.significa "trova tutte le righe che iniziano con ( ^) un carattere arbitrario ( .) seguito da un punto letterale ( \.) ".

Se la linea è 1.02.2017 23:40:00, il modello corrisponderà e 1.verrà sostituito da 01.all'inizio della linea.


Con awk:

Basandosi sul awkcodice parziale nella domanda ...

Questo, come detto, stampa il secondo carattere di ogni riga di input:

$ awk '{ print substr($0, 2, 1) }' file.txt

Possiamo usare il fatto che substr($0, 2, 1)restituisce il secondo carattere e usarlo come condizione:

$ awk 'substr($0, 2, 1) == "." { ... }' file.txt

Ciò che accade { ... }è il codice che antepone $0, che è il contenuto della riga corrente, con uno zero se la condizione precedente è vera:

$ awk 'substr($0, 2, 1) == "." { $0 = "0" $0 }' file.txt

Quindi dobbiamo solo assicurarci che tutte le linee siano stampate:

$ awk 'substr($0, 2, 1) == "." { $0 = "0" $0 } { print }' file.txt

substr($0, 2, 1) == "."Naturalmente la condizione può anche essere cambiata in un'espressione regolare (usiamo esattamente la stessa espressione che abbiamo usato nella sedsoluzione):

$ awk '/^.\./ { $0 = "0" $0 } { print }' file.txt

Alcune persone che pensano che "più corto è sempre meglio" lo scriverebbero come

$ awk '/^.\./ { $0 = "0" $0 } 1' file.txt

(e probabilmente anche rimuovere la maggior parte degli spazi: awk '/^.\./{$0="0"$0}1' file.txt)


1
+1 Il tuo ultimo esempio AWK o il tuo esempio sed sono i modi corretti per farlo. Nota, per chiarezza, che sarebbe solo l'uno o l'altro.
In pausa fino a ulteriore avviso.

A mio parere l'approccio "corretto" (che non violino con spazi e che è più leggero in ogni caso) è la versione finale, sed 's/^.\./0&/' file.txt. Penso che dovresti metterlo all'inizio di questa risposta. Ancora, +1.
Wildcard il

1
@Wildcard Il nostro obiettivo è di favore.
Kusalananda

5

Con sed:

sed -e "/^.\./s/^/0/" file.txt 

Il modello /^.\./cerca qualsiasi carattere e un punto letterale all'inizio della linea ^e, se quello corrisponde, ssostituisci quell'inizio della linea con uno zero, aggiungendo effettivamente lo zero all'inizio.

Il sed expressoin s/.\{0\}/0/è alquanto strano, corrisponde a zero o più copie di qualsiasi cosa e sostituisce con uno zero. Ovviamente il modello corrisponderà in ogni posizione della stringa, ma poiché s///sostituisce solo la prima corrispondenza, funziona come previsto. Un modo singolare per farlo, però.


O con awk, un regex simile funzionerebbe per abbinare la linea, ma possiamo usare substr:

awk 'substr($0, 2, 1) == "." {$0 = "0" $0} 1' file.txt 

Per prima cosa testiamo se il secondo carattere è un punto, quindi aggiungiamo uno zero all'inizio della riga. Quello finale richiama l'azione predefinita di stampa della linea dopo eventuali modifiche.


4

Hai detto awk e sed, ma sembra che tu stia cercando di formattare una data e per questo vorrei usare il datecomando. Per esempio:

echo '1.2.2017 23:40:00' | sed 's/\./\//g' | xargs -0 date '+%m.%d.%Y %T' -d

uscirà

01.02.2017 23:40:00

Il sedcomando nel mezzo cambia i punti in barre per l'input date -d. Le opzioni di formato consentono l'output in quasi tutti i formati desiderati. In %mparticolare lo zero-pad del mese, che è quello che sembra che tu stia cercando di fare.

Come sottolinea Kusalananda:

Ancora più compatto (data GNU e Bash): date -f <(tr '.' '/' <dates.in) '+%m.%d.%Y %T'


2
Bella presa! Ancora più compatto (data GNU e Bash):date -f <(tr '.' '/' <dates.in) '+%m.%d.%Y %T'
Kusalananda

Ogni volta che ho Tagli in miei modelli, ma non Pipes: s|\.|/|g. Altrimenti, come notato sopra: Nice catch, +1
Alex Stragies

2

Una strategia diversa rispetto a quella presentata nelle altre risposte: è possibile utilizzare "." come separatore di campo.

awk -F. '$1 < 10 {printf "0"} {print}' /tmp/in.txt

Puoi giocare a golf per:

awk -F. '$1<10{printf "0"}1' /tmp/in.txt

Per sed, esiste un comando più breve, presentato in un'altra (ottima) risposta.


1
Alternativa: awk -F. '{print ($1<10?0$0:$0)}' file
George Vasiliou,

1

Con sed potrebbe essere

sed 's/^\(.\)\.\(.*\)/0\1.\2/'

Questo servirà ^per ancorare all'inizio della riga, quindi catturare qualsiasi singolo carattere in un gruppo, seguito da un valore letterale ., quindi da qualsiasi altra cosa. Se corrispondiamo al fatto che stampiamo a 0, quindi il nostro primo gruppo di acquisizione (il carattere all'inizio della riga), quindi un .nostro secondo gruppo di acquisizione (il resto della riga)


Non è assolutamente necessario eseguire nessuna di queste acquisizioni. &È tuo amico. Vedi l'esempio sed di Kusalananda.
In pausa fino a ulteriore avviso.

@DennisWilliamson non è necessario, ma dato che ci sono già altri esempi questo mostra un'altra caratteristica sedche potrebbe essere utile in altre situazioni, non solo questo problema specifico
Eric Renouf,
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.