¿Cómo obtengo la última palabra en cada línea con bash?

80

Por ejemplo, tengo un archivo:

$ cat file

i am the first example.

i am the second line.

i do a question about a file.

Y yo necesito:

example, line, file

Intento con "awk" pero el problema es que las palabras están en un espacio diferente

camilo soto
fuente
1
Su "segunda línea" no está en la segunda línea debido a las líneas vacías. Por favor, proporcione ejemplos menos ambiguos en el futuro.
Adrian Frühwirth

Respuestas:

93

Tratar

$ awk 'NF>1{print $NF}' file
example.
line.
file.

Para obtener el resultado en una línea como en su ejemplo, intente:

{
    sub(/\./, ",", $NF)
    str = str$NF
}
END { print str }

salida:

$ awk -f script.awk file
example, line, file, 

Bash puro:

$ while read line; do [ -z "$line" ] && continue ;echo ${line##* }; done < file
example.
line.
file.
Fredrik Pihl
fuente
@Fredrik Pihl, ¿podría agregar explicaciones a cada sección de código, como: "este código imprime el último campo recibido por awk al imprimir $NF"?
Alexej Magura
¿podría explicar echo $ {line ## *};
code4cause
1
@ code4cause - simplemente vaya a gnu.org/software/bash/manual/bash.html y busque ##o simplemente pruébelo en el shell.
Fredrik Pihl
No devuelve nada si solo hay una palabra. $ echo "foo" | awk 'NF> 1 {print $ NF}' $
Ethan Post
85

Puedes hacerlo fácilmente con grep:

grep -oE '[^ ]+$' file

( -Euse expresiones regulares extendidas; envíe -osolo el texto coincidente en lugar de la línea completa)

rici
fuente
3
Debería ser grep -oE '[^ ]+$', desea ver la pestaña aquí debido al comportamiento del navegador, pero de todos modos, esto también considera los espacios de pestaña, o mejor aún, puede hacerlogrep -oE '[^[:space:]]+$'
Nabil Kadimi
32

Puedes hacer algo como esto en awk:

awk '{ print $NF }'

Editar: para evitar una línea vacía:

awk 'NF{ print $NF }'
Hal Canary
fuente
1
Eso también imprimiría las líneas vacías
Fredrik Pihl
12

Otra forma de hacer esto en bash simple es haciendo uso del revcomando de esta manera:

cat file | rev | cut -d" " -f1 | rev | tr -d "." | tr "\n" ","

Básicamente, invierte las líneas del archivo, luego las divide cutusando el espacio como delimitador, toma el primer campo que cutproduce y luego invierte el token nuevamente, usa tr -dpara eliminar caracteres no deseados ytr nuevamente para reemplazar los caracteres de nueva línea con,

Además, puedes evitar al primer gato haciendo:

rev < file | cut -d" " -f1 | rev | tr -d "." | tr "\n" ","
higuaro
fuente
¡Esta es una solución mucho más simple! ¡Aprecio el pensamiento!
Capitán Woof
6

hay muchas maneras. como awkmuestra Solutions, es la solución limpia

La solución sed es eliminar cualquier cosa hasta el último espacio. Entonces, si no hay espacio al final, debería funcionar

sed 's/.* //g' <file>

también puedes evitarlo sedy dar un whilevuelco.

while read line
do [ -z "$line" ] && continue ;
echo $line|rev|cut -f1 -d' '|rev
done < file

lee una línea, la venera, corta la primera (es decir, la última en el original) y la restaura

lo mismo se puede hacer de una manera puramente bash

while read line
do [ -z "$line" ] && continue ;
echo ${line##* }
done < file

se llama expansión de parámetros

abasu
fuente
6

tldr;

$ awk '{print $NF}' file.txt | paste -sd, | sed 's/,/, /g'

Para un archivo como este

$ cat file.txt
The quick brown fox
jumps over
the lazy dog.

el comando dado se imprimirá

fox, over, dog.

Cómo funciona:

  • awk '{print $NF}' : imprime el último campo de cada línea
  • paste -sd,: lee en stdinserie ( -s, un archivo a la vez) y escribe campos delimitados por comas ( -d,)
  • sed 's/,/, /g': ssustituye ","con ", " globalmente (para todos los casos)

Referencias:

rubicks
fuente
Si bien este código puede responder a la pregunta, proporcionar un contexto adicional sobre por qué y / o cómo este código responde a la pregunta mejoraría significativamente su valor a largo plazo. Por favor, editar su respuesta a añadir un poco de explicación.
Toby Speight