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.