Reemplace múltiples espacios con uno usando solo 'tr'

72

Tengo un archivo f1.txt:

ID     Name
1      a
2         b
3   g
6            f

El número de espacios no es fijo. ¿Cuál es la mejor manera de reemplazar todos los espacios en blanco con un espacio usando solo tr?

Esto es lo que tengo hasta ahora:

cat f1.txt | tr -d " "

Pero el resultado es:

IDName
1a
2b
3g
6f

Pero quiero que se vea así:

ID Name
1 a
2 b
3 g
6 f

Por favor intente y evite sed.

gkmohit
fuente
66
¿Por qué es tan importante evitar sed? ¡Usa lo que funcione!
David Richerby
77
Porque sé cómo hacerlo sed. Quería conocer otras formas
:)

Respuestas:

107

Con tr, use la opción de repetición squeeze :

$ tr -s " " < file
ID Name
1 a
2 b
3 g
6 f

O puedes usar una awksolución:

$ awk '{$2=$2};1' file
ID Name
1 a
2 b
3 g
6 f

Cuando cambia un campo en el registro, la awkreconstrucción $0, toma todos los campos y los une, separados por OFS, que es un espacio por defecto.

Eso exprimirá secuencias de espacio y pestañas (y posiblemente otros caracteres en blanco según la configuración regional y la implementación de awk) en un espacio, pero también eliminará los espacios en blanco iniciales y finales de cada línea.

Cuonglm
fuente
1
Esta es una gran solución también. . . No sé cuál elegir ahora: / @Gnouc
gkmohit
Siéntase libre de elegir cualquier solución que le guste y funcione para usted. Una nota de que mi solución es diferente con la respuesta de @ polym.
Cuonglm
1
:)) ¡Hurra! La respuesta de @Gnouc es realmente dinámica, porque él usa awk, puede hacer cualquier cosa. También puedes aceptar su solución. Solo una cosa: Gnouc, ¿podrías explicar qué hace el formato awk en tu comando? ¿También puede agregar tabulaciones / espacios para que la salida se ajuste a la salida esperada de Unknown?
polym
1
@polym: con la última edición de Unknown, parece que solo quiere un espacio, no la salida como lo column -thace. Añadir explicación para awk.
Cuonglm
44
Hay una pequeña diferencia aquí. trreemplazará dos espacios al final de una línea con un solo espacio. awkeliminará todos los espacios finales.
Anne van Rossum
19

Solo usa column:

column -t inputFile

Salida:

ID  Name
1   a
2   b
3   g
6   f
polimero
fuente
Maravilloso y una respuesta rápida :)
gkmohit
1
@ Desconocido ¡Genial estar al servicio :)!
polym
1
@Gnouc wow genial, la columna también toma un archivo como argumento. ¡genial gracias!
polym
¿Cómo puedo obtener la segunda columna solo si quiero? Probé column -t f1.txt | cut -d " " -f2 Pero no era una solución que esperaba
gkmohit
2
Use awk entonces: column -t file | awk '{print $2}'imprime solo la segunda columna
polym
8

Si desea exprimir el "espacio en blanco", querrá usar los juegos de caracteres predefinidos de tr ": blank:" (pestaña y espacio en blanco horizontal) o ": space:" (espacio en blanco vertical):

/bin/echo -e  "val1\t\tval2   val3" | tr -s "[:blank:]"

Se ejecutaron ejemplos en Red Hat 5 (GNU tr).

En mi caso, quería normalizar todo el espacio en blanco en un solo espacio para poder confiar en el espacio como emisor.

Como lo señaló el segundo comentario de dastrobu, me perdí la redacción en la página del manual:

 -s uses the last specified SET, and occurs after translation or deletion.

Esto nos permite eliminar el primer tr. Kudo debe buscar sus paciencia frente a mi densidad.

Antes, análisis del puerto desde la configuración de Redis. archivo:

grep "^port" $redisconf | tr "[:blank:]" " " | tr -s "[:blank:]"  | cut -d" " -f2

Después, con SET2 se especifica con la compresión:

grep "^port" $redisconf | tr -s "[:blank:]" " " | cut -d" " -f2

Salida:

6379

Para más detalles sobre los matices del espacio en blanco

Demuestre dónde solo se produce un apretón cuando intervienen sucesivos caracteres mixtos que entran en la clase de caracteres [: blank:]:

 /usr/bin/printf '%s \t %s' id myname | tr -s "[:blank:]"  | od -cb
0000000   i   d      \t       m   y   n   a   m   e
        151 144 040 011 040 155 171 156 141 155 145
0000013

Nota: Mis dos campos de cadena en el formato printf están separados por 1 espacio, 1 pestaña, 1 espacio. Después de la compresión, esta secuencia todavía existe. En la salida del volcado Octal, esto se representa mediante la secuencia ascii 040 011 040.

usuario3183018
fuente
1
¿Realmente necesitas tr "[:blank:]" " " | tr -s "[:blank:]"? Supongo que la primera parte será suficiente, es decir, tr "[:blank:]" " "ya que normaliza los espacios en blanco y ya realiza la sustitución. Desde la página de manual: "Apriete múltiples ocurrencias de los caracteres [...] Esto ocurre después de que se completa toda la eliminación y traducción".
dastrobu
2
entonces ´tr -s "[: blank:]" "" ´ debería hacerlo, primero traduce todos los espacios en blanco a espacios y luego los exprime. No es necesario un segundo ´tr´.
dastrobu
1
Lo intenté printf 'ID \t Name\n' | tr -s "[:blank:]" " " | od -cb(como lo sugirió @dastrobu) y obtuve ID Name\n(con un espacio) como salida. ¿Realmente lo intentaste @ user3183018?
Scott
1
OK, déjame intentar decir esto de nuevo. Lo hice printf 'ID␣\t␣Name\n' | tr -s "[:blank:]" "␣"  (como lo sugirió @dastrobu), donde representa un espacio, y obtuve ID␣Name\n(con un espacio) como salida. Esto es exactamente igual a su ejemplo de "Puerto <ESPACIO> <TAB> <ESPACIO> 6379", excepto que utilicé las cadenas de encabezado de la pregunta. Me pregunto si lo intentaste  tr -s "[:blank:]"(sin el "␣"argumento final ).
Scott
1
Cuando lo hago printf 'ID \t Name\n' | od -cb, muestra exactamente lo que se supone que debe: ID ⁠  \t ⁠  N a m e \n(es decir,  ID 040 011 040 N a m e\n). Mientras tanto, por su propia evidencia, está cometiendo exactamente el error que supuse que estaba: está ejecutando tr -s "[:blank:]"(es decir,  trcon una opción y  un argumento), en lugar del comando que @dastrobu y yo hemos presentado cuatro veces: tr -s '[:blank:]' '␣'(es decir,  trcon una opción y  dos argumentos ).
Scott
5

¿Quién necesita un programa (que no sea el shell)?

while read a b
do
    echo "$a $b"
done < f1.txt

Si desea que los valores en la segunda columna se alineen, como en la columnrespuesta del polimero , use en printflugar de echo:

while read a b
do
    printf '%-2s %s\n' "$a" "$b"
done < f1.txt
Scott
fuente
1
En primer lugar, en comparación con tr: esta es una sugerencia terriblemente débil en términos de eficiencia, a menos que la entrada sea demasiado pequeña y supere el pequeño costo de trla invocación, lo que sin mencionar cuánto más trabajo lleva escribir. Por último, ¿no diría que esta publicación en realidad no responde la pregunta como se le preguntó? ¿Cuál es la mejor manera de reemplazar todos los espacios en blanco con un espacio usando solo tr?
mikeserv
1
Y además, ¿no podrías hacer algo más fácilmente $IFS? Tal vez como IFS=' <tab>' set -f ; echo $(cat <file):?
mikeserv
2

Esta es una pregunta vieja y resuelta muchas veces. Solo para completar: tuve un problema similar, pero quería pasar líneas a través de la tubería a otro programa. Yo usé xargs .

-L max-lines
   Use at most max-lines nonblank input lines per command line.
   Trailing blanks cause an input line to be logically continued 
   on the next input line.  Implies -x.

por lo que cat f1.txt | xargs -L1parece salida de exactamente lo que quiere.

Martin Seitl
fuente