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

309

Estoy tratando de extraer un cierto (el cuarto) campo de la secuencia de texto ajustada por 'espacio' basada en columnas. Estoy tratando de usar el cutcomando de la siguiente manera:

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

Desafortunadamente, cutno trata varios espacios como un delimitador. Podría haber pasado por awk

awk '{ printf $4; }'

o sed

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

colapsar los espacios, pero me gustaría saber si hay alguna forma de tratar cuty varios delimitadores de forma nativa?

mbaitoff
fuente
12
AWK es el camino a seguir.
Pausado hasta nuevo aviso.
Posible duplicado de la ayuda de corte
Inanc Gumus

Respuestas:

546

Tratar:

tr -s ' ' <text.txt | cut -d ' ' -f4

Desde el tr página manual:

-s, --squeeze-repeats reemplaza cada secuencia de entrada de un carácter repetido
                        que aparece en SET1 con una sola aparición
                        de ese personaje
kev
fuente
24
No hay necesidad de cataquí. Podrías pasar < text.txtdirectamente a tr. en.wikipedia.org/wiki/Cat_%28Unix%29#Useless_use_of_cat
arielf
1
No estoy seguro de que sea más simple, pero va a fusionar, puede renunciar a los cortes -dy traducir directamente de varios caracteres a la pestaña. Por ejemplo: vine aquí buscando una manera de exportar automáticamente mi pantalla:who am i | tr -s ' ()' '\t' | cut -f5
Leo
Esto no elimina los espacios en blanco iniciales / finales (que pueden o no ser deseados, pero generalmente no lo son), en contraste con la solución awk. La solución awk también es mucho más legible y menos detallada.
n.caillou
-1 ADVERTENCIA: ESTO NO ES LO MISMO QUE TRATAR DELIMETROS SECUENCIALES COMO UNO. Compare echo "a b c" | cut -d " " -f2-,echo "a b c" | tr -s " " | cut -d " " -f2-
user541686
96

Como comentas en tu pregunta, awkes realmente el camino a seguir. El uso cutes posible junto con tr -sexprimir espacios, como lo muestra la respuesta de kev .

Sin embargo, permítanme analizar todas las combinaciones posibles para futuros lectores. Las explicaciones se encuentran en la sección Prueba.

tr | cortar

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

awk

awk '{print $4}' file

intento

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

intento

Esto lee los campos secuencialmente. Al usarlo _, indicamos que esta es una variable desechable como una "variable basura" para ignorar estos campos. De esta manera, almacenamos $myfieldcomo el cuarto 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 atrapa tres grupos de espacios y no espacios con ([^ ]*[ ]*){3}. Luego, atrapa lo que viene hasta un espacio como el cuarto campo, con el que finalmente se imprime \1.

$ sed -r 's/^([^ ]*[ ]*){3}([^ ]*).*/\2/' a
1
2
3
4
fedorqui 'así que deja de dañar'
fuente
2
awkno solo es elegante y simple, también se incluye en VMware ESXi, donde trfalta.
user121391
2
@ user121391 ¡otra razón más para usar awk!
fedorqui 'SO deja de dañar'
@fedorqui Nunca he oído hablar del guión bajo como "variable basura". ¿Me puede dar más información / referencia sobre esto?
BryKKan
1
@BryKKan Lo aprendí en Greg's ¿Cómo puedo leer un archivo (flujo de datos, variable) línea por línea (y / o campo por campo)? : Algunas personas usan la variable desechable _ como una "variable basura" para ignorar los campos. También (o cualquier otra variable) también se puede usar más de una vez en un solo readcomando, si no nos importa lo que implica . Puede ser cualquier cosa, es solo que de alguna manera se convirtió en estándar en lugar de junk_varo whatever:)
fedorqui 'SO deja de dañar'
25

solución más corta / amigable

Después de frustrarme con las demasiadas limitaciones de cut, escribí mi propio reemplazo, que pedí cuts"cortar con esteroides".

cortes proporciona lo que probablemente sea la solución más minimalista para este y muchos otros problemas relacionados con cortar / pegar.

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

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

$ cuts 2 text.txt
2
2

cuts apoya:

  • Detección automática 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 en paralelo (no es necesario invocar por pasteseparado)
  • 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 escritura minimalista requerida

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

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

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

arielf
fuente
4

Este Perl one-liner muestra cuán estrechamente se relaciona Perl con awk:

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

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

Chris Koknat
fuente
3

Con versiones de lo cutque sé, no, esto no es posible. cutes principalmente útil para analizar archivos donde el separador no es un espacio en blanco (por ejemplo /etc/passwd) y que tienen un número fijo de campos. Dos separadores seguidos significan un campo vacío, y eso también se aplica al espacio en blanco.

Benoit
fuente