¿Cómo recorto los espacios en blanco iniciales y finales de cada línea de alguna salida?

155

Me gustaría eliminar todos los espacios y pestañas iniciales y finales de cada línea en una salida.

¿Existe una herramienta simple como trimsi pudiera canalizar mi salida?

Archivo de ejemplo:

test space at back 
 test space at front
TAB at end  
    TAB at front
sequence of some    space in the middle
some empty lines with differing TABS and spaces:





 test space at both ends 
rubo77
fuente
1
Para cualquiera que busque una solución para eliminar nuevas líneas, ese es un problema diferente. Por definición, una nueva línea crea una nueva línea de texto. Por lo tanto, una línea de texto no puede contener una nueva línea. La pregunta que desea hacer es cómo eliminar una nueva línea desde el principio o el final de una cadena: stackoverflow.com/questions/369758 , o cómo eliminar líneas en blanco o líneas que son solo espacios en blanco: serverfault.com/questions/252921
Tony

Respuestas:

201
awk '{$1=$1;print}'

o más corto:

awk '{$1=$1};1'

Recortaría el espacio inicial y final o los caracteres de tabulación 1 y también exprimiría secuencias de tabulaciones y espacios en un solo espacio.

Eso funciona porque cuando asigna algo a uno de los campos , awkreconstruye todo el registro (tal como se imprime print) uniendo todos los campos ( $1, ..., $NF) con OFS(espacio por defecto).

1 (y posiblemente otros caracteres en blanco según la configuración regional y la awkimplementación)

Stéphane Chazelas
fuente
2
El punto y coma en el segundo ejemplo es superfluo. Podría usar:awk '{$1=$1}1'
Brian
8
@Brian, no, ;se requiere en la sintaxis awk estándar
Stéphane Chazelas
Interesante ... gawk, mawk y OS X's awk no admiten punto y coma. (Al menos para mis versiones (1.2, 4.1.1 y 20070501, respectivamente)
Brian
1
Lo único que no me gusta de este enfoque es que pierdes espacios repetitivos dentro de la línea. Por ejemplo,echo -e 'foo \t bar' | awk '{$1=$1};1'
user.friendly
2
echo ' hello ' | xargs
JREAM
44

El comando se puede condensar así si está utilizando GNU sed:

$ sed 's/^[ \t]*//;s/[ \t]*$//' < file

Ejemplo

Aquí está el comando anterior en acción.

$ echo -e " \t   blahblah  \t  " | sed 's/^[ \t]*//;s/[ \t]*$//'
blahblah

Puede usar hexdumppara confirmar que el sedcomando está eliminando los caracteres deseados correctamente.

$ echo -e " \t   blahblah  \t  " | sed 's/^[ \t]*//;s/[ \t]*$//' | hexdump -C
00000000  62 6c 61 68 62 6c 61 68  0a                       |blahblah.|
00000009

Clases de personajes

También puede usar nombres de clase de caracteres en lugar de enumerar literalmente los conjuntos como este [ \t]:

$ sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//' < file

Ejemplo

$ echo -e " \t   blahblah  \t  " | sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//'

La mayoría de las herramientas GNU que hacen uso de expresiones regulares (regex) admiten estas clases.

 [[:alnum:]]  - [A-Za-z0-9]     Alphanumeric characters
 [[:alpha:]]  - [A-Za-z]        Alphabetic characters
 [[:blank:]]  - [ \x09]         Space or tab characters only
 [[:cntrl:]]  - [\x00-\x19\x7F] Control characters
 [[:digit:]]  - [0-9]           Numeric characters
 [[:graph:]]  - [!-~]           Printable and visible characters
 [[:lower:]]  - [a-z]           Lower-case alphabetic characters
 [[:print:]]  - [ -~]           Printable (non-Control) characters
 [[:punct:]]  - [!-/:-@[-`{-~]  Punctuation characters
 [[:space:]]  - [ \t\v\f]       All whitespace chars
 [[:upper:]]  - [A-Z]           Upper-case alphabetic characters
 [[:xdigit:]] - [0-9a-fA-F]     Hexadecimal digit characters

Usar estos en lugar de conjuntos literales siempre parece una pérdida de espacio, pero si le preocupa que su código sea portátil o tenga que lidiar con conjuntos de caracteres alternativos (piense en internacional), es probable que desee usar los nombres de clase en lugar.

Referencias

slm
fuente
Tenga en cuenta que [[:space:]]no es equivalente a [ \t]en el caso general (unicode, etc.). [[:space:]]probablemente será mucho más lento (ya que hay muchos más tipos de espacios en blanco en Unicode que solo ' 'y '\t'). Lo mismo para todos los demás.
Olivier Dulac
sed 's/^[ \t]*//'No es portátil. En realidad, POSIX incluso requiere que se elimine una secuencia de espacio, barra diagonal inversa o tcaracteres, y eso es lo que GNU sedtambién hace cuando POSIXLY_CORRECTestá en el entorno.
Stéphane Chazelas
¿Qué sucede si quiero recortar caracteres de nueva línea? '\ n \ n text \ n \ n'
Eugene Biryukov
Me gusta la solución sed debido a la falta de otros efectos secundarios como en la solución awk. La primera variación no funciona cuando lo probé en bash en OSX jsut ahora, pero la versión de clase de caracteres funciona:sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//'
a Tony
@EugeneBiryukov ver mi comentario en la publicación original
Tony
23

Según lo sugerido por Stéphane Chazelas en la respuesta aceptada, ahora puede
crear un script /usr/local/bin/trim:

#!/bin/bash
awk '{$1=$1};1'

y otorgue a ese archivo derechos ejecutables:

chmod +x /usr/local/bin/trim

Ahora puede pasar cada salida a, trimpor ejemplo:

cat file | trim

(para los comentarios a continuación: usé esto antes: while read i; do echo "$i"; done
que también funciona bien, pero es menos eficiente)

rubo77
fuente
1
Buena suerte si su archivo es enorme y / o contiene barras invertidas.
don_crissti
1
@don_crissti: ¿podría comentar un poco más ?, ¿qué solución sería mejor para archivos grandes y cómo podría modificar mi solución si el archivo contiene barras diagonales inversas?
rubo77
3
Vas a tener que usar while read -r linepara preservar barras invertidas y aun entonces ... . En cuanto a los archivos / velocidad enormes, realmente, elegiste la peor solución. No creo que haya nada peor por ahí. Vea las respuestas en ¿Por qué es una mala práctica utilizar un bucle de shell para procesar texto? incluido mi comentario sobre la última respuesta donde agregué un enlace a un punto de referencia de velocidad. Las sedrespuestas aquí están perfectamente bien IMO y mucho mejor que read.
don_crissti
@don_crissti ... y / o tiene líneas que comienzan con -y seguidas de combinaciones de 1 o más caracteres e, E o n, y / o contiene caracteres NUL. Además, se omitirá una línea no terminada después de la última línea nueva.
Stéphane Chazelas
1
También puede agregar un alias en / etc / profile (o su ~ / .bashrc o ~ / .zshrc, etc.) alias trim = "awk '{\ $ 1 = \ $ 1}; 1'"
Jeff Clayton
22

Los xargs sin argumentos hacen eso.

Ejemplo:

trimmed_string=$(echo "no_trimmed_string" | xargs) 
Newton_Jose
fuente
1
Esto también contrae múltiples espacios dentro de una línea, lo que no se solicitó en la pregunta
roaima
1
@roaima: verdadero, pero la respuesta aceptada también exprime espacios (que no se solicitó en la pregunta). Creo que el verdadero problema aquí es que xargsno se entregará si la entrada contiene barras invertidas y comillas simples.
don_crissti
Sin embargo, @don_crissti no significa que la respuesta aceptada responda correctamente a la pregunta que se le hizo. Pero en este caso aquí no se marcó como una advertencia, mientras que en la respuesta aceptada sí. Espero haber resaltado el hecho en caso de que sea relevante para un futuro lector.
roaima
También se rompe en comillas simples, comillas dobles, caracteres de barra invertida. También ejecuta una o más echoinvocaciones. Algunas implementaciones de eco también procesarán opciones y / o barras invertidas ... Eso también solo funciona para la entrada de una sola línea.
Stéphane Chazelas
17
sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//'

Si está leyendo una línea en una variable de shell, readya lo hace a menos que se indique lo contrario .

Gilles
fuente
1
+1 para read. Por lo tanto, si se cat file | while read i; do echo $i; done
conecta
1
@rubo, excepto que en su ejemplo la variable sin comillas también es reprocesada por el shell. Úselo echo "$i"para ver el verdadero efecto de laread
roaima
13

Si almacena líneas como variables, puede usar bash para hacer el trabajo:

eliminar espacios en blanco iniciales de una cadena:

shopt -s extglob
echo ${text##+([[:space:]])}

eliminar espacios en blanco finales de una cadena:

shopt -s extglob
echo ${text%%+([[:space:]])}

eliminar todos los espacios en blanco de una cadena:

echo ${text//[[:space:]]}
Łukasz Rajchel
fuente
Eliminar todos los espacios en blanco de una cadena no es lo mismo que eliminar los espacios iniciales y finales (como en cuestión).
catpnosis
Con mucho, la mejor solución: solo requiere bash builtins y no tenedores de proceso externos.
user259412
2
Agradable. Los scripts se ejecutan MUCHO más rápido si no tienen que acceder a programas externos (como awk o sed). Esto funciona también con versiones "modernas" (93u +) de ksh.
user1683793
9

Para eliminar todos los espacios iniciales y finales de una línea dada gracias a una herramienta 'canalizada', puedo identificar 3 formas diferentes que no son completamente equivalentes. Estas diferencias se refieren a los espacios entre las palabras de la línea de entrada. Dependiendo del comportamiento esperado, harás tu elección.

Ejemplos

Para explicar las diferencias, consideremos esta línea de entrada ficticia:

"   \t  A   \tB\tC   \t  "

tr

$ echo -e "   \t  A   \tB\tC   \t  " | tr -d "[:blank:]"
ABC

trEs realmente un comando simple. En este caso, elimina cualquier espacio o carácter de tabulación.

awk

$ echo -e "   \t  A   \tB\tC   \t  " | awk '{$1=$1};1'
A B C

awk elimina espacios iniciales y finales y los comprime en un solo espacio cada espacio entre palabras.

sed

$ echo -e "   \t  A   \tB\tC   \t  " | sed 's/^[ \t]*//;s/[ \t]*$//'
A       B   C

En este caso, sedelimina los espacios iniciales y posteriores sin tocar ningún espacio entre las palabras.

Observación:

En el caso de una palabra por línea, trhace el trabajo.

frozar
fuente
Sin embargo
mantenimiento el
+1 para obtener una lista de soluciones con su salida (a veces inesperada).
Tony
@ user61382 esto es bastante tarde, pero vea mi comentario en la publicación original.
Tony
@highmaintenance: use [:space:], en lugar de [: blank:], para el comando tr, como:, ... | tr -d [:space:]para eliminar nuevas líneas también. (ver: man tr)
tron5
6

sed es una gran herramienta para eso:

                        # substitute ("s/")
sed 's/^[[:blank:]]*//; # parts of lines that start ("^")  with a space/tab 
     s/[[:blank:]]*$//' # or end ("$") with a space/tab
                        # with nothing (/)

Puede usarlo para su caso ya sea canalizando en el texto, por ejemplo

<file sed -e 's/^[[...

o actuando sobre él 'en línea' si tu sedes el GNU:

sed -i 's/...' file

pero cambiar la fuente de esta manera es "peligroso" ya que puede ser irrecuperable cuando no funciona correctamente (¡o incluso cuando lo hace!), así que primero haga una copia de seguridad (o use el -i.bakque también tiene la ventaja de ser portátil para algunos BSD sed) !

Michael Durrant
fuente
2

comando de traducción funcionaría

cat file | tr -d [:blank:]
Srinagesh
fuente
44
Este comando no es correcto ya que elimina todos los espacios del archivo, no solo los espacios en blanco iniciales / finales.
Brian Redbeard
@BrianRedbeard Estás en lo correcto. Esta sigue siendo una respuesta útil para una cadena monolítica, sin espacios.
Anthony Rutledge
0

Si la cadena que uno está tratando de recortar es corta y continua / contigua, simplemente puede pasarla como parámetro a cualquier función bash:

    trim(){
        echo $@
    }

    a="     some random string   "

    echo ">>`trim $a`<<"
Output
>>some random string<<
Subrata Das
fuente