¿Cómo hacer que el comando 'cortar' trate los mismos delimitadores secuenciales como uno solo?
Estoy intentando extraer un determinado campo (el cuarto) del flujo de texto ajustado por "espacio" basado en columnas. Estoy intentando usar el cut
comando de la siguiente manera:
cat text.txt | cut -d " " -f 4
Lamentablemente, cut
no trata varios espacios como un delimitador. Podría haber hablado a través de awk.
awk '{ printf $4; }'
o sentado
sed -E "s/[[:space:]]+/ /g"
para colapsar los espacios, pero me gustaría saber si hay alguna forma de lidiar con cut
varios delimitadores de forma nativa.
Intentar:
tr -s ' ' <text.txt | cut -d ' ' -f4
Desde la tr
página de 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
Como comentas en tu pregunta, awk
es realmente el camino a seguir. Es posible usarlo cut
junto con tr -s
apretar espacios, como muestra la respuesta de Kev .
Sin embargo, permítanme repasar 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 usar _
indicamos que esta es una variable desechable como "variable basura" para ignorar estos campos. De esta manera, lo almacenamos $myfield
como el cuarto campo del 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 ningún espacio con ([^ ]*[ ]*){3}
. Luego, captura todo 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
solución más corta/más amigable
Después de sentirme frustrado por las demasiadas limitaciones de cut
, escribí mi propio reemplazo, al que pedí cuts
"reducir los esteroides".
cuts proporciona lo que probablemente sea la solución más minimalista para este y muchos otros problemas relacionados de cortar/pegar.
Un ejemplo, entre 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
apoya:
- detección automática de los delimitadores de campos más comunes en archivos (+ capacidad de anular los valores predeterminados)
- delimitadores coincidentes de múltiples caracteres, caracteres mixtos y expresiones regulares
- extraer columnas de múltiples archivos con delimitadores mixtos
- desplazamientos desde el final de la línea (usando números negativos) además del inicio de la línea
- Pegado automático de columnas una al lado de la otra (no es necesario invocarlas
paste
por separado) - soporte para reordenamiento de campos
- un archivo de configuración donde los usuarios pueden cambiar sus preferencias personales
- gran énfasis en la facilidad de uso y la 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/
Esta frase breve de Perl muestra cuán estrechamente relacionado está Perl con awk:
perl -lane 'print $F[3]' text.txt
Sin embargo, la @F
matriz de división automática comienza en el índice $F[0]
, mientras que los campos awk comienzan con$1
Con versiones de cut
que conozco no, esto no es posible. cut
Es 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 a los espacios en blanco.