Cómo eliminar la última columna de un archivo en Linux


25

Quiero eliminar la última columna de un archivo txt, aunque no sé cuál es el número de columna. ¿Cómo podría hacer esto?

Ejemplo:

Entrada:

1223 1234 1323 ... 2222 123
1233 1234 1233 ... 3444 125
0000 5553 3455 ... 2334 222

Y quiero que mi salida sea:

1223 1234 1323 ... 2222
1233 1234 1233 ... 3444
0000 5553 3455 ... 2334

Hay muchas maneras de hacer this..please añadir un ejemplo y el resultado esperado de ella ..
heemayl

@heemayl ok, lo hice
zara

Gracias ... ¿están separadas las pestañas de las columnas o el espacio?
heemayl

@heemayl space es deliminator
zara

Respuestas:


43

Con awk:

awk 'NF{NF-=1};1' <in >out

o:

awk 'NF{NF--};1' <in >out

o:

awk 'NF{--NF};1' <in >out

Aunque esto parece vudú, funciona. Hay tres partes en cada uno de estos comandos awk.

La primera es NF, que es una condición previa para la segunda parte. NFes una variable que contiene el número de campos en una línea. En AWK, las cosas son ciertas si no son 0 o una cadena vacía "". Por lo tanto, la segunda parte (donde NFse disminuye) solo ocurre si NFno es 0.

La segunda parte (ya sea NF-=1 NF--o --NF) está restando uno de la NFvariable. Esto evita que se imprima el último campo, porque cuando cambia un campo (eliminando el último campo en este caso), awkreconstruya $0, concatene todos los campos separados por espacio de forma predeterminada. $0ya no contenía el último campo.

La parte final es 1. No es mágico, solo se usa como una expresión que significa true. Si una awkexpresión se evalúa como verdadera sin ninguna acción asociada, la awkacción predeterminada es print $0.


@JJoao: Ah, gracias, se olvidó --. Una nota, actualmente, necesita ;1para POSIX compatible.
Cuonglm

Mi instinto inicial sería usar un bucle for, pero esto es mucho más conciso e inteligente.
Sergiy Kolodyazhnyy

55
Vale la pena señalar que si está utilizando un delimitador no predeterminado, deberá realizar algunos cambios. Suponiendo que ,sea ​​su delimitador:awk -F',' 'BEGIN { OFS = FS }; NF { NF -= 1 }; 1' < in > out
Sr. Llama

1
El efecto de disminuir NF es un comportamiento indefinido de POSIX: obtendrá un resultado diferente según el awk que esté ejecutando. Algunos awks eliminarán el último campo como desee, algunos no harán nada y otros podrían informar un error de sintaxis o cualquier otra cosa.
Ed Morton

16

Utilizando grepcon PCRE:

$ grep -Po '.*(?=\s+[^\s]+$)' file.txt 
1223 1234 1323 ... 2222
1233 1234 1233 ... 3444
0000 5553 3455 ... 2334

Usando GNU sed:

$ sed -r 's/(.*)\s+[^\s]+$/\1/' file.txt 
1223 1234 1323 ... 2222
1233 1234 1233 ... 3444
0000 5553 3455 ... 2334

1
@ramin Claro ... ¿podría hacer una nueva pregunta (así es como funciona este sitio) :)
heemayl

@ramin ¿Le da alguna restricción de tiempo o alguna advertencia?
heemayl

¡dice que esto está fuera de la pregunta estándar!
zara

@ramin Ok ... déjame contactar a un administrador, puede ser que puedan ayudarte con eso ... por cierto, ¿verificaste algún control de calidad anterior con respecto a tu pregunta? es posible que la pregunta ya se haya hecho y respondido ..
heemayl

3
No haga preguntas súper básicas como " ¿cómo puedo cambiar el nombre de un archivo en Linux ". Utiliza Google.
Christoffer Hammarström

11

Usando Perl:

perl -lane '$,=" ";pop(@F);print(@F)' in

Usando rev+ cut:

rev in | cut -d ' ' -f 2- | rev

5

Usando GNU sed:

sed -r 's/\s+\S+$//' input.txt

En términos más generales, este funciona con el BSD sed en OSX, así como con GNU sed:

sed 's/[[:space:]]\{1,\}[^[:space:]]\{1,\}$//' input.txt

1

Si el delimitador siempre es un carácter único (por lo que dos o más delimitadores consecutivos designan campos vacíos), podría headsimplemente la primera línea de su archivo de entrada, contar los delimitadores ( ndelimitadores significa que el número de campos es n+1) y luego usar cutpara imprimir desde el 1campo st hasta el ncampo th (penúltimo), por ejemplo, con entrada delimitada por tabulaciones:

n=$(head -n 1 infile | tr -dc \\t | tr \\t \\n | wc -l)
cut -f1-$n infile > outfile

o por ejemplo con un archivo csv :

n=$(head -n 1 infile | tr -dc , | tr , \\n | wc -l)
cut -d, -f1-$n infile > outfile

Ejecutaré algunos puntos de referencia más adelante si tengo tiempo, pero con una gran aportación, creo que esta solución debería ser más rápida que otras soluciones que usan expresiones regulares, ya que esta realiza un procesamiento mínimo en la primera línea para obtener el no. de campos y luego utiliza el cutque está optimizado para este trabajo.


1

Portablemente puede usar cualquiera de estos:

sed 's/[[:space:]]*[^[:space:]]*$//' file

awk '{sub(/[[:space:]]*[^[:space:]]*$/,"")}1' file

0

Usando vim:

Abrir archivo en vim

vim <filename> 

Vaya a la primera fila, en caso de que el cursor se coloque en otro lugar.

gg

Cree una macro llamada "q" qq, que vaya al final de la línea actual $, luego regrese al último espacio F(F mayúscula, seguido de ESPACIO literal), luego borre de la posición actual hasta el final de la línea, Dbaje a la siguiente línea jy detener la grabación de macro con q.

qq$F Djq

Ahora podemos repetir nuestra macro con @qcada línea.
También podemos presionar @@para repetir la última macro o incluso más fácil:

99@q

para repetir la macro 99 veces.
Nota: El número no debe coincidir exactamente con las líneas.


0

Para las personas que tienen un problema similar pero con diferentes separadores de campo, este awkmétodo preservará el separador de campo correctamente:

$ cat file 
foo.bar.baz
baz.bar.foo
$ awk -F'.' 'sub(FS $NF,x)' file
foo.bar
baz.bar
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.