¿Cómo hacer que el comando ‘cortar’ trate los mismos delimitadores secuenciales como uno solo?

Estoy tratando de extraer un cierto (el cuarto) campo de la secuencia de texto ajustada en columna y ‘espacio’. Estoy tratando de usar el comando de cut de la siguiente manera:

cat text.txt | cut -d " " -f 4

Desafortunadamente, cut no trata varios espacios como un delimitador. Pude haber canalizado a través de awk

awk '{ printf $4; }'

o sed

sed -E "s/[[:space:]]+/ /g"

para colapsar los espacios, pero me gustaría saber si hay alguna forma de tratar con el cut y varios delimitadores de forma nativa?

Tratar:

 tr -s ' '  

Desde la página de tr man:

 -s, --squeeze-repeats reemplaza cada secuencia de entrada de un carácter repetido
                         que se enumera en SET1 con una sola aparición
                         de ese personaje

Cuando comentas en tu pregunta, awk es realmente el camino a seguir. Para usar el cut es posible junto con tr -s para exprimir espacios, como lo muestra la respuesta de kev .

Sin embargo, permítanme pasar por todas las combinaciones posibles para lectores futuros. Las explicaciones están en la sección Prueba.

tr | cortar

 tr -s ' ' < file | cut -d' ' -f4 

awk

 awk '{print $4}' file 

bash

 while read -r _ _ _ myfield _ do echo "forth field: $myfield" done < file 

sed

 sed -r 's/^([^ ]*[ ]*){3}([^ ]*).*/\2/' file 

Pruebas

Dado este archivo, probemos los comandos:

 $ cat a this is line 1 more text this is line 2 more text this is line 3 more text this is line 4 more text 

tr | cortar

 $ cut -d' ' -f4 a is # it does not show what we want! $ tr -s ' ' < a | cut -d' ' -f4 1 2 # this makes it! 3 4 $ 

awk

 $ awk '{print $4}' a 1 2 3 4 

bash

Esto lee los campos secuencialmente. Al usar _ indicamos que esta es una variable desechable como una "variable no deseada" para ignorar estos campos. De esta manera, almacenamos $myfield como el 4to campo en el archivo, sin importar los espacios entre ellos.

 $ while read -r _ _ _ a _; do echo "4th field: $a"; done < a 4th field: 1 4th field: 2 4th field: 3 4th field: 4 

sed

Esto captura tres grupos de espacios y no espacios con ([^ ]*[ ]*){3} . Luego, atrapa lo que venga hasta un espacio como el 4 ° campo, que finalmente se imprime con \1 .

 $ sed -r 's/^([^ ]*[ ]*){3}([^ ]*).*/\2/' a 1 2 3 4 

la solución más corta / más amigable

Después de frustrarme con las demasiadas limitaciones del cut , escribí mi propio reemplazo, que llamé cuts para “cortar esteroides”.

cortes proporciona lo que probablemente sea la solución más minimalista para este y muchos otros problemas de corte / pegado relacionados.

Un ejemplo, de muchos, que aborda esta pregunta en particular:

 $ cat text.txt 0 1 2 3 0 1 2 3 4 $ cuts 2 text.txt 2 2 

cuts soportes:

  • autodetección de los delimitadores de campo más comunes en los archivos (+ capacidad para anular los valores predeterminados)
  • Delimitadores coincidentes multi-char, mixed-char y regex
  • extracción de columnas de múltiples archivos con delimitadores mixtos
  • compensaciones desde el final de la línea (usando números negativos) además del inicio de la línea
  • pegado automático de columnas al lado del otro (no es necesario invocar el paste separado)
  • soporte para reordenamiento de campo
  • un archivo de configuración donde los usuarios pueden cambiar sus preferencias personales
  • gran énfasis en la facilidad de uso y la escritura mínima requerida

y mucho más. Ninguno de los cuales es proporcionado por cut estándar.

Ver también: https://stackoverflow.com/a/24543231/1296044

Fuente y documentación (software libre): http://arielf.github.io/cuts/

Este anuncio único de Perl muestra cuán estrechamente se relaciona Perl con awk:

 perl -lane 'print $F[3]' text.txt 

Sin embargo, la matriz @F autosplit comienza en el índice $F[0] mientras que los campos awk comienzan con $1

Con las versiones de cut que conozco, no, esto no es posible. cut es principalmente útil para analizar archivos en los que el separador no es un espacio en blanco (por ejemplo, /etc/passwd ) y que tienen un número fijo de campos. Dos separadores en una fila significan un campo vacío, y eso también se aplica a los espacios en blanco.