Cuando utiliza un procesador de textos, formatear el texto para que las líneas quepan en el espacio disponible en el dispositivo de destino no debería ser un problema. Pero cuando se trabaja en la terminal, las cosas no son tan fáciles.
Por supuesto, siempre puedes dividir líneas a mano usando tu editor de texto favorito, pero esto rara vez es deseable e incluso está fuera de discusión para el procesamiento automatizado.
Con suerte, el POSIXfold
utilidad y el GNU/BSDfmt
El comando puede ayudarle a redistribuir un texto para que las líneas no excedan una longitud determinada.
¿Qué es una línea en Unix?
Antes de entrar en los detalles delfold
yfmt
comandos, definamos primero de qué estamos hablando. En un archivo de texto, una línea está formada por una cantidad arbitraria de caracteres, seguida de una secuencia especial de control de nueva línea (a veces llamada EOL, por fin de línea).
En sistemas tipo Unix, la secuencia de control de fin de línea se compone del (único y único) carácter de avance de línea, a veces abreviado LF o escriton
siguiendo una convención heredada del lenguaje C. A nivel binario, el carácter de avance de línea se representa como un byte que contiene el0a
valor hexadecimal.
Puedes comprobarlo fácilmente usando elhexdump
utilidad que usaremos mucho en este artículo. Ésta puede ser una buena ocasión para familiarizarse con esa herramienta. Puede, por ejemplo, examinar los volcados hexadecimales a continuación para encontrar cuántos caracteres de nueva línea ha enviado cada comando de eco. Una vez que crea que tiene la solución, simplemente vuelva a intentar esos comandos sin el| hexdump -C
parte para ver si lo adivinaste correctamente.
sh$ echo hello | hexdump -C
00000000 68 65 6c 6c 6f 0a |hello.|
00000006
sh$ echo -n hello | hexdump -C
00000000 68 65 6c 6c 6f |hello|
00000005
sh$ echo -e 'hellon' | hexdump -C
00000000 68 65 6c 6c 6f 0a 0a |hello..|
00000007
Vale la pena mencionar en este punto que diferentes sistemas operativos pueden seguir reglas diferentes con respecto a la secuencia de nueva línea. Como hemos visto anteriormente, los sistemas operativos tipo Unix utilizan el carácter de salto de línea, pero Windows, como la mayoría de los protocolos de Internet, utiliza dos caracteres: el par retorno de carro+salto de línea (CRLF, o0d 0a
, orn
). En Mac OS “clásico” (hasta MacOS 9.2 inclusive a principios de la década de 2000), las computadoras Apple usaban CR solo como carácter de nueva línea. Otras computadoras heredadas también usaban el par LFCR, o incluso secuencias de bytes completamente diferentes en el caso de sistemas más antiguos incompatibles con ASCII. Afortunadamente, estos últimos son reliquias del pasado y dudo que vea alguna computadora EBCDIC en uso hoy en día.
Hablando de historia, si tiene curiosidad, el uso de los caracteres de control de “retorno de carro” y “avance de línea” se remonta al código Baudot utilizado en la era del teletipo. Es posible que haya visto el teletipo representado en películas antiguas como una interfaz para una computadora del tamaño de una habitación. Pero incluso antes de eso, los teletipos se utilizaban de forma “independiente” para comunicaciones punto a punto o multipunto. En aquella época, un terminal típico parecía una pesada máquina de escribir con un teclado mecánico, papel y un carro móvil que sostenía el cabezal de impresión. Para comenzar una nueva línea, el carro debe regresarse al extremo izquierdo y el papel debe moverse hacia arriba girando la platina (a veces llamada "cilindro"). Esos dos movimientos fueron controlados por dos sistemas electromecánicos independientes, los caracteres de control de avance de línea y retorno de carro estaban conectados directamente a esas dos partes del dispositivo. Dado que mover el carro requiere más tiempo que girar la platina, era lógico iniciar primero el retorno del carro. Separar las dos funciones también tuvo un par de efectos secundarios interesantes, como permitir la sobreimpresión (enviando solo el CR) o la transmisión eficiente de “doble interlínea” (un CR + dos LF).
La definición al comienzo de esta sección describe principalmente qué es una línea lógica. Sin embargo, la mayoría de las veces, esa línea lógica “arbitrariamente larga” debe enviarse a un dispositivo físico como una pantalla o una impresora, donde el espacio disponible es limitado. Mostrar líneas lógicas cortas en un dispositivo que tiene líneas físicas más grandes no es un problema. Simplemente hay un espacio no utilizado a la derecha del texto. Pero, ¿qué pasa si intentas mostrar una línea de texto más grande que el espacio disponible en el dispositivo? En realidad, existen dos soluciones, cada una con sus inconvenientes:
- En primer lugar, el dispositivo puedetruncarlas líneas en su tamaño físico, ocultando así parte del contenido al usuario. Algunas impresoras hacen eso, especialmente las impresoras tontas (y sí, todavía se utilizan impresoras matriciales de puntos básicas en la actualidad, ¡especialmente en entornos hostiles o sucios!)
- La segunda opción para mostrar líneas lógicas largas es dividirlas en varias líneas físicas. Se llamaajuste de líneaporque las líneas parecen envolver el espacio disponible, un efecto particularmente visible si puedes cambiar el tamaño de la pantalla como cuando trabajas con un emulador de terminal.
Esos comportamientos automáticos son bastante útiles, pero todavía hay ocasiones en las que deseas romper líneas largas en una posición determinada, independientemente del tamaño físico del dispositivo. Por ejemplo, puede resultar útil porque desea que los saltos de línea se produzcan en la misma posición tanto en la pantalla como en la impresora. O porque desea que su texto se use en una aplicación que no realiza ajuste de línea (por ejemplo, si incrusta texto mediante programación en un archivo SVG). Finalmente, lo creas o no, todavía hay muchos protocolos de comunicación que imponen un ancho de línea máximo en las transmisiones, incluidos los populares como IRC y SMTP (si alguna vez viste el error 550 Se excedió la longitud máxima de línea, sabes lo que estoy hablando sobre). Por eso, hay muchas ocasiones en las que es necesario dividir líneas largas en trozos más pequeños. Este es el trabajo del POSIXfold
dominio.
El comando de plegar
Cuando se utiliza sin ninguna opción, elfold
El comando agrega secuencias de control de nueva línea adicionales para garantizar que ninguna línea exceda el límite de 80 caracteres. Para que quede claro, una línea contendrá como máximo 80 caracteres más la secuencia de nueva línea.
Si ha descargado el material de soporte para ese artículo, puede intentarlo usted mismo:
sh$ fold POSIX.txt | head -5
The Portable Operating System Interface (POSIX)[1] is a family of standards spec
ified by the IEEE Computer Society for maintaining compatibility between operati
ng systems. POSIX defines the application programming interface (API), along wit
h command line shells and utility interfaces, for software compatibility with va
riants of Unix and other operating systems.[2][3]
# Using AWK to prefix each line by its length:
sh$ fold POSIX.txt | awk '{ printf("%3d %sn", length($0), $0) }'
80 The Portable Operating System Interface (POSIX)[1] is a family of standards spec
80 ified by the IEEE Computer Society for maintaining compatibility between operati
80 ng systems. POSIX defines the application programming interface (API), along wit
80 h command line shells and utility interfaces, for software compatibility with va
49 riants of Unix and other operating systems.[2][3]
0
80 The standards emerged from a project that began circa 1985. Richard Stallman sug
80 gested the name POSIX to the IEEE instead of former IEEE-IX. The committee found
71 it more easily pronounceable and memorable, and thus adopted it.[2][4]
Puede cambiar la longitud máxima de la línea de salida utilizando el-w
opción. Probablemente lo más interesante sea el uso de la-s
opción para garantizar que las líneas se rompan en el límite de una palabra. Comparemos el resultado sin y con el-s
opción cuando se aplica al segundo párrafo de nuestro texto de muestra:
# Without `-s` option: fold will break lines at the specified position
# Broken lines have exactly the required width
sh$ awk -vRS='' 'NR==2' POSIX.txt |
fold -w 30 | awk '{ printf("%3d %sn", length($0), $0) }'
30 The standards emerged from a p
30 roject that began circa 1985.
30 Richard Stallman suggested the
30 name POSIX to the IEEE instea
30 d of former IEEE-IX. The commi
30 ttee found it more easily pron
30 ounceable and memorable, and t
21 hus adopted it.[2][4]
# With `-s` option: fold will break lines at the last space before the specified position
# Broken lines are shorter or equal to the required width
awk -vRS='' 'NR==2' POSIX.txt |
fold -s -w 30 | awk '{ printf("%3d %sn", length($0), $0) }'
29 The standards emerged from a
25 project that began circa
23 1985. Richard Stallman
28 suggested the name POSIX to
27 the IEEE instead of former
29 IEEE-IX. The committee found
29 it more easily pronounceable
24 and memorable, and thus
17 adopted it.[2][4]
Obviamente, si su texto contiene palabras más largas que la longitud máxima de línea, el comando plegar no podrá respetar la longitud máxima de línea.-s
bandera. En ese caso, elfold
La utilidad dividirá las palabras de gran tamaño en la posición máxima, asegurándose siempre de que ninguna línea exceda el ancho máximo permitido.
sh$ echo "It's Supercalifragilisticexpialidocious!" | fold -sw 10
It's
Supercalif
ragilistic
expialidoc
ious!
Caracteres multibyte
Como la mayoría, si no todas, las utilidades principales, lafold
El comando fue diseñado en un momento en que un carácter equivalía a un byte. Sin embargo, este ya no es el caso en la informática moderna, especialmente con la adopción generalizada de UTF-8. Algo que conduce a problemas desafortunados:
# Just in case, check first the relevant locale
# settings are properly defined
debian-9.4$ locale | grep LC_CTYPE
LC_CTYPE="en_US.utf8"
# Everything is OK, unfortunately...
debian-9.4$ echo élève | fold -w2
é
l�
�v
e
La palabra “élève” (la palabra francesa para “estudiante”) contiene dos letras acentuadas:é
(LETRA E MINÚSCULA LATINA CON AGUDA) yè
(LETRA E MINÚSCULA LATINA CON TUMBA). Usando el juego de caracteres UTF-8, esas letras se codifican usando dos bytes cada una (respectivamente,c3 a9
yc3 a8
), en lugar de sólo un byte como es el caso de las letras latinas no acentuadas. Puede comprobarlo examinando los bytes sin procesar utilizando elhexdump
utilidad. Debería poder identificar las secuencias de bytes correspondientes alé
yè
caracteres. Por cierto, es posible que también veas en ese volcado de nuestro viejo amigo el carácter de avance de línea cuyo código hexadecimal se mencionó anteriormente:
debian-9.4$ echo élève | hexdump -C
00000000 c3 a9 6c c3 a8 76 65 0a |..l..ve.|
00000008
Examinemos ahora el resultado producido por el comando plegar:
debian-9.4$ echo élève | fold -w2
é
l�
�v
e
debian-9.4$ echo élève | fold -w 2 | hexdump -C
00000000 c3 a9 0a 6c c3 0a a8 76 0a 65 0a |...l...v.e.|
0000000b
Evidentemente, el resultado producido por lafold
El comando es un poco más largo que la cadena de caracteres original debido a las nuevas líneas adicionales: respectivamente, 11 bytes de largo y 8 bytes de largo, incluidas las nuevas líneas. Hablando de eso, en la salida delfold
comando es posible que haya visto el avance de línea (0a
) carácter que aparece cada dos bytes. Y este es exactamente el problema: el comando plegar rompía líneas en posiciones de bytes, no en posiciones de caracteres. ¡Incluso si esa interrupción ocurre en medio de un carácter de varios bytes! No es necesario mencionar que la salida resultante ya no es un flujo de bytes UTF-8 válido, de ahí el uso del carácter de reemplazo Unicode (�
) por mi terminal como marcador de posición para las secuencias de bytes no válidas.
como para elcut
comando que escribí hace unas semanas, esta es una limitación en la implementación GNU delfold
utilidad y esto está claramente en oposición con las especificaciones POSIX que establecen explícitamente que "Una línea no se romperá en medio de un carácter".
Así aparece el GNUfold
La implementación solo trata correctamente con codificaciones de caracteres de un byte de longitud fija (US-ASCII, Latin1, etc.). Como solución alternativa, si existe un juego de caracteres adecuado, puede transcodificar su texto a una codificación de caracteres de un byte antes de procesarlo y luego volver a codificarlo a UTF-8. Sin embargo, esto es cuanto menos engorroso:
debian-9.4$ echo élève |
iconv -t latin1 | fold -w 2 |
iconv -f latin1 | hexdump -C
00000000 c3 a9 6c 0a c3 a8 76 0a 65 0a |..l...v.e.|
0000000a
debian-9.4$ echo élève |
iconv -t latin1 | fold -w 2 |
iconv -f latin1
él
èv
e
Como todo esto fue bastante decepcionante, decidí verificar el comportamiento de otras implementaciones. Como suele ser el caso, la implementación OpenBSD delfold
La utilidad es mucho mejor en ese sentido ya que es compatible con POSIX y respetará lasLC_CTYPE
configuración regional para manejar correctamente los caracteres multibyte:
openbsd-6.3$ locale | grep LC_CTYPE
LC_CTYPE=en_US.UTF-8
openbsd-6.3$ echo élève | fold -w 2 C
él
èv
e
openbsd-6.3$ echo élève | fold -w 2 | hexdump -C
00000000 c3 a9 6c 0a c3 a8 76 0a 65 0a |..l...v.e.|
0000000a
Como puede ver, la implementación de OpenBSD corta correctamente las líneas en las posiciones de los caracteres, independientemente del número de bytes necesarios para codificarlas. En la inmensa mayoría de los casos de uso, esto es lo que desea. Sin embargo, si necesita el comportamiento heredado (es decir, estilo GNU) considerando un byte como un carácter, puede cambiar temporalmente la configuración regional actual a la denominada configuración regional POSIX (identificada por la constante "POSIX" o, por razones históricas, "C ”):
openbsd-6.3$ echo élève | LC_ALL=C fold -w 2
é
l�
�v
e
openbsd-6.3$ echo élève | LC_ALL=C fold -w 2 | hexdump -C
00000000 c3 a9 0a 6c c3 0a a8 76 0a 65 0a |...l...v.e.|
0000000b
Finalmente, POSIX especifica el-b
bandera, que indica alfold
utilidad para medir la longitud de línea en bytes, pero que, sin embargo, garantiza caracteres multibyte (de acuerdo con la actualLC_CTYPE
configuración local) no se romperá.
Como ejercicio, le recomiendo encarecidamente que se tome el tiempo necesario para encontrar las diferencias a nivel de bytes entre el resultado obtenido al cambiar la configuración regional actual a "C" (arriba) y el resultado obtenido al usar el-b
bandera en su lugar (abajo). Puede que sea sutil. Pero hay una diferencia:
openbsd-6.3$ echo élève | fold -b -w 2 | hexdump -C
00000000 c3 a9 0a 6c 0a c3 a8 0a 76 65 0a |...l....ve.|
0000000b
Entonces, ¿encontraste la diferencia?
Bueno, al cambiar la configuración regional a “C”, elfold
La utilidad no se ocupó de las secuencias de varios bytes, ya que, por definición, cuando la configuración regional es "C", las herramientas deben asumir que un carácter es un byte. Por lo tanto, se puede agregar una nueva línea en cualquier lugar, incluso en medio de una secuencia de bytes que se habría considerado como un carácter multibyte en otra codificación de caracteres. Esto es exactamente lo que sucedió cuando la herramienta produjo elc3 0a a8
secuencia de bytes: los dos bytesc3 a8
se entienden como un carácter cuandoLC_CTYPE
define la codificación de caracteres como UTF-8. Pero la misma secuencia de bytes se ve como dos caracteres en la configuración regional "C":
# Bytes are bytes. They don't change so
# the byte count is the same whatever is the locale
openbsd-6.3$ printf "%d bytesn" $(echo -n é | LC_ALL=en_US.UTF-8 wc -c)
2 bytes
openbsd-6.3$ printf "%d bytesn" $(echo -n é | LC_ALL=C wc -c)
2 bytes
# The interpretation of the bytes may change depending on the encoding
# so the corresponding character count will change
openbsd-6.3$ printf "%d charsn" $(echo -n é | LC_ALL=en_US.UTF-8 wc -m)
1 chars
openbsd-6.3$ printf "%d charsn" $(echo -n é | LC_ALL=C wc -m)
2 chars
Por otra parte, con el-b
opción, la herramienta aún debería ser compatible con varios bytes. Esa opción solo cambia es la forma en que cuenta las posiciones, esta vez en bytes, en lugar de caracteres como es por defecto. En ese caso, dado que las secuencias de varios bytes no se dividen, la salida resultante sigue siendo una secuencia de caracteres válida (de acuerdo con la configuración actual).LC_CTYPE
configuración local):
openbsd-6.3$ echo élève | fold -b -w 2
é
l
è
ve
Lo has visto, ya no aparece más el carácter de reemplazo Unicode (�
), y no perdimos ningún carácter significativo en el proceso, a costa de terminar esta vez con líneas que contienen un número variable de caracteres y un número variable de bytes. Finalmente, lo único que garantiza la herramienta es que no haya más bytes por línea de los solicitados con el-w
opción. Algo que podemos comprobar usando elwc
herramienta:
openbsd-6.3$ echo élève | fold -b -w 2 | while read line; do
> printf "%3d bytes %3d chars %sn"
> $(echo -n $line | wc -c)
> $(echo -n $line | wc -m)
> $line
> done
2 bytes 1 chars é
1 bytes 1 chars l
2 bytes 1 chars è
2 bytes 2 chars ve
Una vez más, tómate el tiempo necesario para estudiar el ejemplo anterior. Hace uso de los comandos printf y wc que no expliqué en detalle anteriormente. Entonces, si las cosas no están lo suficientemente claras, ¡no dudes en utilizar la sección de comentarios para pedir algunas explicaciones!
Por curiosidad, revisé el-b
bandera en mi caja Debian usando GNUfold
implementación:
debian-9.4$ echo élève | fold -w 2 | hexdump -C
00000000 c3 a9 0a 6c c3 0a a8 76 0a 65 0a |...l...v.e.|
0000000b
debian-9.4$ echo élève | fold -b -w 2 | hexdump -C
00000000 c3 a9 0a 6c c3 0a a8 76 0a 65 0a |...l...v.e.|
0000000b
No pierda su tiempo tratando de encontrar una diferencia entre las-b
y no--b
Versiones de ese ejemplo: hemos visto que la implementación de GNU Fold no admite multibyte, por lo que ambos resultados son idénticos. Si no estás convencido de eso, tal vez puedas usar eldiff -s
comando para permitir que su computadora lo confirme. Si lo hace, utilice la sección de comentarios para compartir el comando que utilizó con los demás lectores.
De todos modos, ¿eso significa que-b
opción inútil en la implementación GNU delfold
¿utilidad? Bueno, leyendo más detenidamente la documentación de GNU Coreutils para elfold
comando, encontré el-b
La opción solo trata con caracteres especiales como la tabulación o el retroceso, que cuentan respectivamente entre 1 y 8 (uno a ocho) o -1 (menos uno) en el modo normal, pero siempre cuentan como 1 posición en el modo byte. ¿Confuso? Entonces, tal vez podríamos tomarnos un tiempo para explicar esto con más detalles.
Manejo de tabulación y retroceso
La mayoría de los archivos de texto con los que trabajará sólo contienen caracteres imprimibles y secuencias de final de línea. Sin embargo, ocasionalmente puede suceder que algunos caracteres de control encuentren su camino hacia sus datos. El carácter de tabulación (t
) es uno de ellos. Mucho más raramente, el retroceso (b
) también se puede encontrar. Todavía lo menciono aquí porque, como su nombre lo indica, es un carácter de control que hace que el cursor se mueva una posición hacia atrás (hacia la izquierda), mientras que la mayoría de los otros caracteres lo hacen hacia adelante (hacia la derecha).
sh$ echo -e 'tab:[t] backspace:[b]'
tab:[ ] backspace:]
Es posible que esto no sea visible en su navegador, por lo que le recomiendo encarecidamente que lo pruebe en su terminal. Pero los caracteres de tabulación (t
) ocupa varias posiciones en la salida. ¿Y el retroceso? Parece haber algo extraño en el resultado, ¿no? Así que ralenticemos un poco las cosas, dividiendo la cadena de texto en varias partes e insertando algunassleep
entre ellos:
# For that to work, type all the commands on the same line
# or using backslashes like here if you split them into
# several (physical) lines:
sh$ echo -ne 'tab:[t] backspace:[';
sleep 1; echo -ne 'b';
sleep 1; echo -n ']';
sleep 1; echo ''
¿DE ACUERDO? ¿Lo viste esta vez? Descompongamos la secuencia de los eventos:
- La primera cadena de caracteres se muestra "normalmente" hasta el segundo corchete de apertura. debido a la
-n
bandera, laecho
El comando no envía un carácter de nueva línea, por lo que el cursor permanece en la misma línea. - Primer sueño.
- Se emite retroceso, lo que hace que el cursor retroceda una posición. Todavía no hay una nueva línea, por lo que el cursor permanece en la misma línea.
- Segundo sueño.
- Se muestra el corchete de cierre, sobrescribiendo el de apertura.
- Tercer sueño.
- En ausencia del
-n
opción, la últimaecho
El comando finalmente envía el carácter de nueva línea y el cursor se mueve a la siguiente línea, donde se mostrará el símbolo del shell.
Por supuesto, se puede obtener un efecto igualmente genial usando un retorno de carro, si lo recuerdas:
sh$ echo -n 'hello'; sleep 1; echo -e 'rgood bye'
good bye
Estoy bastante seguro de que ya has visto algunas utilidades de línea de comandos como curl y wget que muestran una barra de progreso. Hacen su magia usando una combinación deb
y/or
.
Por interesante que la discusión pueda ser por sí sola, el punto aquí fue entender que manejar esos personajes puede ser un desafío para elfold
utilidad. Con suerte, el estándar POSIX define las reglas:
El recuento actual de ancho de línea se reducirá en uno, aunque el recuento nunca pasará a ser negativo. La utilidad de plegado no insertará un inmediatamente antes o después de cualquier . El recuento actual del ancho de línea se establecerá en cero. La utilidad de plegado no insertará un inmediatamente antes o después de cualquier . Cada encontrado hará avanzar el puntero de posición de la columna hasta la siguiente tabulación. Las tabulaciones deben estar en cada posición de columna n de modo que n módulo 8 sea igual a 1.
Todos esos tratamientos especiales están deshabilitados cuando se utiliza el-b
opción. En este caso, los caracteres de control cuentan (correctamente) para un byte y, por lo tanto, aumentan el contador de posición en uno y sólo uno, como cualquier otro carácter.
Para una mejor comprensión, te dejo investigar por ti mismo los dos ejemplos siguientes (tal vez usando elhexdump
utilidad). Ahora debería poder encontrar por qué “hola” se ha convertido en “infierno” y dónde está exactamente la “i” en la salida (tal como está allí, ¡incluso si no puede verla!). Como siempre, si necesita ayuda , o simplemente si quieres compartir tus hallazgos, la sección de comentarios es tuya.
# Why "hello" has become "hell"? where is the "i"?
sh$ echo -e 'hellorgood bibye' | fold -w4
hell
good
bye
# Why "hello" has become "hell"? where is the "i"?
# Why the second line seems to be made of only two chars instead of 4?
sh$ echo -e 'hellorgood bibye' | fold -bw4
hell
go
od b
ye
Otras limitaciones
Elfold
El comando que hemos estudiado hasta ahora fue diseñado para dividir líneas lógicas largas en líneas físicas más pequeñas, especialmente para fines de formato.
Eso significa que asume que cada línea de entrada es autónoma y puede dividirse independientemente de las otras líneas. Esto no es siempre el caso, sin embargo. Por ejemplo, consideremos ese correo muy importante que recibí:
sh$ cat MAIL.txt
Dear friends,
Have a nice day!
We are manufactuer for event chairs and tables, more than 10 years experience.
We supply all kinds of wooden, resin and metal event chairs, include chiavari
chairs, cross back chairs, folding chairs, napoleon chairs, phoenix chairs, etc.
Our chairs and tables are of high quality and competitively priced.
If you need our products, welcome to contact me;we are happy to make you special
offer.
Best Regards
Doris
sh$ awk '{ length>maxlen && (maxlen=length) } END { print maxlen }' MAIL.txt
81
Obviamente, las líneas ya estaban divididas hasta alcanzar un ancho fijo. Elawk
El comando me dijo que el ancho máximo de línea aquí era... 81 caracteres, excluyendo la nueva secuencia de líneas. Sí, eso fue lo suficientemente extraño como para volver a verificarlo: de hecho, la línea más larga tiene 80 caracteres imprimibles más un espacio adicional en la posición 81 y solo después de eso está el carácter de salto de línea. ¡Probablemente el personal de TI que trabaja en nombre de este “fabricante” de sillas podría beneficiarse de leer este artículo!
De todos modos, suponiendo que me gustaría cambiar el formato de ese correo electrónico, tendré problemas con elfold
comando debido a los saltos de línea existentes. Te dejo comprobar los dos comandos siguientes si quieres, pero ninguno de ellos funcionará como se esperaba:
sh$ fold -sw 100 MAIL.txt
sh$ fold -sw 60 MAIL.txt
El primero simplemente no hará nada ya que todas las líneas ya tienen menos de 100 caracteres. Con respecto al segundo comando, dividirá las líneas en la posición 60 pero mantendrá los caracteres de nueva línea ya existentes para que el resultado sea irregular. Será particularmente visible en el tercer párrafo:
sh$ awk -v RS='' 'NR==3' MAIL.txt |
fold -sw 60 |
awk '{ length>maxlen && (maxlen=length); print length, $0 }'
53 We supply all kinds of wooden, resin and metal event
25 chairs, include chiavari
60 chairs, cross back chairs, folding chairs, napoleon chairs,
20 phoenix chairs, etc.
La primera línea del tercer párrafo estaba dividida en la posición 53, lo que es consistente con nuestro ancho máximo de 60 caracteres por línea. Sin embargo, la segunda línea se rompió en la posición 25 porque ese carácter de nueva línea ya estaba presente en el archivo de entrada. En otras palabras, para cambiar el tamaño de los párrafos correctamente, primero debemos volver a unir las líneas antes de dividirlas en la nueva posición de destino.
Puedes usarsed
oawk
para volver a unir las líneas. Y de hecho, como lo mencioné en el video introductorio, ese sería un buen desafío para usted. Así que no dude en publicar su solución en la sección de comentarios.
En cuanto a mí, seguiré un camino más fácil mirando elfmt
dominio. Si bien no es un comando estándar POSIX, está disponible tanto en el mundo GNU como en BSD. Por lo tanto, hay muchas posibilidades de que se pueda utilizar en su sistema. Lamentablemente, la falta de estandarización tendrá algunas implicaciones negativas, como veremos más adelante. Pero por ahora, concentrémonos en las partes buenas.
El comando fmt
Elfmt
El mando está más evolucionado que elfold
comando y tiene más opciones de formato. La parte más interesante es que puede identificar párrafos en el archivo de entrada basándose en las líneas vacías. Eso significa que todas las líneas hasta la siguiente línea vacía (o el final del archivo) se unirán primero para formar lo que llamé anteriormente una "línea lógica" del texto. Sólo después de eso, elfmt
El comando dividirá el texto en la posición solicitada.
Veamos ahora qué cambiará cuando se aplique al segundo párrafo de mi correo de ejemplo:
sh$ awk -v RS='' 'NR==3' MAIL.txt |
fmt -w 60 |
awk '{ length>maxlen && (maxlen=length); print length, $0 }'
60 We supply all kinds of wooden, resin and metal event chairs,
59 include chiavari chairs, cross back chairs, folding chairs,
37 napoleon chairs, phoenix chairs, etc.
Anecdóticamente, elfmt
comando aceptado para incluir una palabra más en la primera línea. Pero lo más interesante es que la segunda línea ahora está llena, lo que significa que el carácter de nueva línea que ya estaba presente en el archivo de entrada después de que se haya descartado la palabra “chiavari” (¿qué es esto?). Por supuesto, las cosas no son perfectas, y elfmt
El algoritmo de detección de párrafos a veces genera falsos positivos, como en los saludos al final del correo (línea 14 del resultado):
sh$ fmt -w 60 MAIL.txt | cat -n
1 Dear friends,
2
3 Have a nice day! We are manufactuer for event chairs and
4 tables, more than 10 years experience.
5
6 We supply all kinds of wooden, resin and metal event chairs,
7 include chiavari chairs, cross back chairs, folding chairs,
8 napoleon chairs, phoenix chairs, etc.
9
10 Our chairs and tables are of high quality and competitively
11 priced. If you need our products, welcome to contact me;we
12 are happy to make you special offer.
13
14 Best Regards Doris
dije antes elfmt
El comando era una herramienta de formato de texto más evolucionada que elfold
utilidad. De hecho, es. Puede que no sea obvio a primera vista, pero si observa detenidamente las líneas 10 y 11, podrá notar que se usan dos espacios después del punto, lo que impone una convención muy discutida de usar dos espacios al final de una oración. No entraré en ese debate para saber si deberías o no usar dos espacios entre oraciones, pero aquí no tienes otra opción: que yo sepa, ninguna de las implementaciones comunes de lafmt
El comando ofrece una bandera para desactivar el doble espacio después de una oración. ¿A menos que exista esa opción en alguna parte y me la perdí? Si este es el caso, estaré feliz de que me lo hagas saber usando la sección de comentarios: como escritor francés, nunca usé el “doble espacio” después de una oración…
Más opciones de FMT
Elfmt
La utilidad está diseñada con más capacidades de formato que el comando plegar. Sin embargo, al no estar definido POSIX, existen importantes incompatibilidades entre las opciones GNU y BSD.
Por ejemplo, el-c
La opción se usa en el mundo BSD para centrar el texto, mientras que en GNU Coreutilsfmt
habilita el modo de margen de corona, “preservando la sangría de las dos primeras líneas dentro de un párrafo, y alineando el margen izquierdo de cada línea posterior con el de la segunda línea. “
Te dejo experimentar por ti mismo con el GNU.fmt -c
si quieres. Personalmente, encuentro que la función de centrado de texto BSD es más interesante de estudiar debido a alguna rareza: de hecho, en OpenBSD,fmt -c
centrará el texto según el ancho objetivo, ¡pero sin redistribuirlo! Por lo tanto, el siguiente comando no funcionará como esperaba:
openbsd-6.3$ fmt -c -w 60 MAIL.txt
Dear friends,
Have a nice day!
We are manufactuer for event chairs and tables, more than 10 years experience.
We supply all kinds of wooden, resin and metal event chairs, include chiavari
chairs, cross back chairs, folding chairs, napoleon chairs, phoenix chairs, etc.
Our chairs and tables are of high quality and competitively priced.
If you need our products, welcome to contact me;we are happy to make you special
offer.
Best Regards
Doris
Si realmente desea redistribuir el texto para un ancho máximo de 60 caracteres y centrar el resultado, tendrá que usar dos instancias delfmt
dominio:
openbsd-6.3$ fmt -w 60 MAIL.txt | fmt -c -w60
Dear friends,
Have a nice day! We are manufactuer for event chairs and
tables, more than 10 years experience.
We supply all kinds of wooden, resin and metal event chairs,
include chiavari chairs, cross back chairs, folding chairs,
napoleon chairs, phoenix chairs, etc.
Our chairs and tables are of high quality and competitively
priced. If you need our products, welcome to contact me;we
are happy to make you special offer.
Best Regards Doris
No haré aquí una lista exhaustiva de las diferencias entre GNU y BSD.fmt
implementaciones… ¡esencialmente porque todas las opciones son diferentes! Excepto por supuesto el-w
opción. Hablando de eso, se me olvidó mencionar-N
donde N es un número entero es un atajo para-wN
. Además, puedes usar ese atajo tanto con elfold
yfmt
comandos: entonces, si fuiste lo suficientemente perseverante como para leer su artículo hasta este punto, como recompensa ahora puedes sorprender a tus amigos guardando una (!) pulsación de tecla completa la próxima vez que uses una de esas utilidades:
debian-9.4$ fmt -50 POSIX.txt | head -5
The Portable Operating System Interface
(POSIX)[1] is a family of standards specified
by the IEEE Computer Society for maintaining
compatibility between operating systems. POSIX
defines the application programming interface
openbsd-6.3$ fmt -50 POSIX.txt | head -5
The Portable Operating System Interface (POSIX)[1]
is a family of standards specified by the IEEE
Computer Society for maintaining compatibility
between operating systems. POSIX defines the
application programming interface (API), along
debian-9.4$ fold -sw50 POSIX.txt | head -5
The Portable Operating System Interface
(POSIX)[1] is a family of standards specified by
the IEEE Computer Society for maintaining
compatibility between operating systems. POSIX
defines the application programming interface
openbsd-6.3$ fold -sw50 POSIX.txt | head -5
The Portable Operating System Interface
(POSIX)[1] is a family of standards specified by
the IEEE Computer Society for maintaining
compatibility between operating systems. POSIX
defines the application programming interface
Como última palabra, también puedes notar en ese último ejemplo las versiones GNU y BSD delfmt
La utilidad está utilizando un algoritmo de formato diferente, lo que produce un resultado diferente. Por otro lado, cuanto más simplefold
El algoritmo produce resultados consistentes entre las implementaciones. Todo eso quiere decir que si la portabilidad es una prima, debes ceñirte a lafold
comando, eventualmente completado por algunas otras utilidades POSIX. Pero si necesita funciones más sofisticadas y puede permitirse el lujo de romper la compatibilidad, consulte el manual de lafmt
comando específico para su propio sistema. ¡Y háganos saber si descubrió algún uso divertido o creativo para esas opciones específicas del proveedor!