awk sed si declaración

9

Estoy tratando de agregar 0 al principio, SI hay un "." en el segundo caracter de esa línea. No pude combinar estos dos;

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

mostrando el segundo personaje

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

agregando un cero al principio.

Debería haber un "si el segundo carácter es un punto".

archivo de muestra:

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

final:

01.02.2017 23:40:00
10.02.2017 23:40:00
G. Ahmet
fuente

Respuestas:

12

Podemos usar cualquiera de sedo awkpara resolver completamente el problema.


Con sed:

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

Cuando &ocurre en la parte de reemplazo del comando de sustitución ( s), se expandirá a la parte de la línea de entrada que coincida con la parte del patrón del comando.

La expresión regular ^.\.significa "hacer coincidir todas las líneas que comienzan con ( ^) un carácter arbitrario ( .) seguido de un punto literal ( \.) ".

Si la línea es 1.02.2017 23:40:00, el patrón coincidirá y 1.sería reemplazado por 01.al comienzo de la línea.


Con awk:

Sobre la base del awkcódigo parcial en la pregunta ...

Esto, como se indicó, imprimirá el segundo carácter de cada línea de entrada:

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

Podemos usar el hecho de que substr($0, 2, 1)devuelve el segundo carácter y usarlo como condición:

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

Lo que entra { ... }es un código que precede $0, que es el contenido de la línea actual, con un cero si la condición anterior es verdadera:

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

Entonces solo necesitamos asegurarnos de que todas las líneas estén impresas:

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

La condición substr($0, 2, 1) == ".", por supuesto, también puede cambiarse a una expresión regular (usamos exactamente la misma expresión que usamos en la sedsolución):

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

Algunas personas que piensan que "más corto siempre es mejor" escribirían eso como

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

(y probablemente también eliminar la mayoría de espacios: awk '/^.\./{$0="0"$0}1' file.txt)

Kusalananda
fuente
1
+1 Su último ejemplo AWK o su ejemplo sed son las formas correctas de hacer esto. Tenga en cuenta, para mayor claridad, que solo sería uno u otro.
Pausado hasta nuevo aviso.
En mi opinión, el enfoque "correcto" (que no lo hace el violín con espacios y que es un peso más ligero de todos modos) es su versión final, sed 's/^.\./0&/' file.txt. Creo que deberías poner eso al comienzo de esta respuesta. Aún así, +1.
Comodín el
1
@Wildcard Nuestro objetivo es complacer.
Kusalananda
5

Con sed:

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

El patrón /^.\./busca cualquier carácter y un punto literal al comienzo de la línea ^, y si eso coincide, ssustituya ese inicio de línea con un cero, agregando efectivamente el cero al comienzo.

El sed expresoin s/.\{0\}/0/es algo extraño, coincide con cero o más copias de cualquier cosa y lo reemplaza por un cero. El patrón, por supuesto, coincidirá en todas las posiciones de la cadena, pero como s///solo reemplaza la primera coincidencia, funciona como se esperaba. Sin embargo, es una forma pintoresca de hacerlo.


O con awk, una expresión regular similar funcionaría para coincidir con la línea, pero podemos usar substr:

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

Primero probamos si el segundo carácter es un punto, luego agregamos un cero al frente de la línea si es así. El último invoca la acción predeterminada de imprimir la línea después de cualquier modificación.

ilkkachu
fuente
4

Dijiste awk y sed, pero parece que estás tratando de formatear una fecha y para eso usaría el datecomando. Por ejemplo:

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

saldrá

01.02.2017 23:40:00

El sedcomando en el medio cambia los puntos a barras para la entrada date -d. Las opciones de formato permiten la salida en casi cualquier formato que desee. En %mparticular, hará cero el mes, que es lo que parece que estás tratando de hacer.

Como Kusalananda señala:

Aún más compacto (fecha GNU y Bash): date -f <(tr '.' '/' <dates.in) '+%m.%d.%Y %T'

bmb
fuente
2
¡Buena atrapada! Aún más compacto (fecha GNU y Bash):date -f <(tr '.' '/' <dates.in) '+%m.%d.%Y %T'
Kusalananda
Cada vez que tengo rayas verticales en mis patrones, pero no hay Tubos: s|\.|/|g. De lo contrario, como se señaló anteriormente: Buena captura, +1
Alex Stragies
2

Una estrategia diferente a la presentada en las otras respuestas: podría usar "." como el separador de campo.

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

Podrías jugar golf para:

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

Para sed, hay un comando más corto, presentado en otra respuesta (excelente).

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

Con sed podría ser

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

Esto se usará ^para anclar al comienzo de la línea, luego capturará cualquier carácter individual en un grupo, seguido de un literal ., y luego cualquier otra cosa. Si coincidimos con que imprimimos un 0, entonces nuestro primer grupo de captura (el personaje al comienzo de la línea), luego un .segundo grupo de captura (el resto de la línea)

Eric Renouf
fuente
No es necesario hacer nada de esa captura. &es tu amigo. Ver el ejemplo sed de Kusalananda.
Pausado hasta nuevo aviso.
@DennisWilliamson no es necesario, pero dado que hay otros ejemplos, esto muestra otra característica sedque podría ser útil en otras situaciones, no solo este problema específico
Eric Renouf