AWK: ajusta líneas a 72 caracteres

7
$ awk 'length > 72' {HOW TO PRINT THE LINEs IN PCS?} msg

es decir, quiero que se agregue \ndespués de 72 caracteres y continúe, por lo que inicialmente es posible que deba eliminar todos los mensajes individuales \ny agregarlos. Puede ser más fácil ser más fácil con otra herramienta, pero intentemos awk.

[Actualizar]

Williamson proporcionó la respuesta correcta pero se necesitó ayuda para leerla. Divido el problema en partes con ejemplos más simples, a continuación.

  1. ¿Por qué el siguiente código impreso \ten ambos casos gsubdebería sustituir las cosas? x es un archivo ficticio, algunos 0 impares al final.

  2. Al atacar la línea line = $0 \n more = getline \n gsub("\t"," ")en la respuesta de Williamson , lineaparentemente obtiene un stdout completo mientras se moreobtiene el valor emergente $0, ¿verdad?

Código de la parte 1

$ gawk '{ hallo="tjena\t tjena2"; gsub("\t"," "); }; END {print hallo; gsub("\t", ""); hallo=hallo gsub("\t",""); print hallo }' x
tjena  tjena2
tjena  tjena20
Comunidad
fuente

Respuestas:

4

Aquí hay una secuencia de comandos AWK que envuelve líneas largas y vuelve a envolver el resto, así como las líneas cortas:

awk -v WIDTH=72 '
{
    gsub("\t"," ")
    $0 = line $0
    while (length <= WIDTH) {
        line = $0
        more = getline
        gsub("\t"," ")
        if (more)
            $0 = line " " $0
        else
            $0 = line
            break
    }
    while (length >= WIDTH) {
        print substr($0,1,WIDTH)
        $0 = substr($0,WIDTH+1)
    }
    line = $0 " "
}

END {
    print
}
'

Hay un script de Perl disponible en CPAN que hace un muy buen trabajo al reformatear el texto. Se llama paradj ( archivos individuales ). Para hacer guiones, también necesitará TeX::Hyphen.

SWITCHES
--------
The available switches are:

--width=n (or -w=n or -w n)
    Line width is n chars long

--left (or -l)
    Output is left-justified (default)

--right (or -r)
    Output is right-justified

--centered (or -c)
    Output is centered

--both (or -b)
    Output is both left- and right-justified

--indent=n (or -i=n or -i n)
    Leave n spaces for initial indention (defaults to 0)

--newline (or -n)
    Insert blank lines between paragraphs

--hyphenate (or -h)
    Hyphenate word that doesn't fit on a line

Aquí hay una diferencia de algunos cambios que hice para admitir una opción de margen izquierdo:

12c12
< my ($indent, $newline);
---
> my ($indent, $margin, $newline);
15a16
>   "margin:i" => \$margin,
21a23
> $margin = 0 if (!$margin);
149a152
>     print " " x $margin;
187a191,193
>   print "--margin=n (or -m=n or -m n)  Add a left margin of n ";
>   print "spaces\n";
>   print "                                (defaults to 0)\n";
Pausado hasta nuevo aviso.
fuente
Por cierto, levanté el guión de Gilles para usarlo como parte del mío.
Pausado hasta nuevo aviso.
13

No estoy usando awk

Entiendo que esto puede ser solo una parte de un problema mayor que está tratando de resolver usando awko simplemente un intento de comprender mejor, pero si realmente solo desea mantener la longitud de su línea en 72 columnas, hay una herramienta mucho mejor.

La fmtherramienta se diseñó específicamente con esto en mente:

fmt --width=72 filename

fmtTambién intentará romper las líneas en lugares razonables, haciendo que la salida sea más agradable de leer. Consulte la infopágina para obtener más detalles sobre lo que se fmtconsidera "lugares razonables".

Steven D
fuente
GNU fmt no admite codificaciones multibyte, widthsignifica bytes, no caracteres.
Phillip Kovalev el
44
los usuarios de macOS pueden usarfold -s -w 72
Edward Loveall el
@EdwardLoveall foldtambién funcionará en sistemas GNU (viene con GNU coreutils).
heemayl
3

Awk es un lenguaje completo de Turing, y no uno particularmente ofuscado, por lo que es bastante fácil truncar líneas. Aquí hay una versión sencilla e imperativa.

awk -v WIDTH=72 '
{
    while (length>WIDTH) {
        print substr($0,1,WIDTH);
        $0=substr($0,WIDTH+1);
    }
    print;
}
'

Si desea truncar líneas entre palabras, puede codificarlas en awk, pero reconocer palabras no es trivial (por razones que tienen más que ver con lenguajes naturales que con dificultad algorítmica). Muchos sistemas tienen una utilidad llamada fmtque hace exactamente eso.

Gilles 'SO- deja de ser malvado'
fuente
Je, estaba editando mi respuesta para incluir esto mientras escribías la tuya. Creo que solo eliminaré mis ediciones. Realmente desearía poder ver cuando alguien más estaba escribiendo una respuesta.
Steven D
1
Estrictamente hablando, su script no está truncando líneas; más bien, está envolviendo largas líneas, pero no re-envolviendo el resto.
Pausado hasta nuevo aviso.
2

Aquí hay una función Awk que se rompe en espacios:

function wrap(text,   q, y, z) {
  while (text) {
    q = match(text, / |$/); y += q
    if (y > 72) {
      z = z RS; y = q - 1
    }
    else if (z) z = z FS
    z = z substr(text, 1, q - 1)
    text = substr(text, q + 1)
  }
  return z
}

Sorprendentemente, esto es más eficaz que fold o fmt .

Fuente

Steven Penny
fuente
2

Usted preguntó por qué el awkcódigo emitía pestañas y de dónde provenía el cero.

  1. El código no modifica la hellocadena con las gsub()llamadas. Con dos argumentos, gsub()actúa sobre $0. Para modificar realmente la hallovariable, use gsub(..., ..., hallo).

  2. Obtiene el cero al final de la cadena porque gsub()devuelve el número de sustituciones realizadas, y en un punto agrega este número al valor de hallo.

Soy consciente de al menos tres utilidades que son específicamente para envolver y formatear párrafos de texto:

  1. fold, "filtro para líneas plegables", que es una utilidad POSIX estándar . Simplemente inserta nuevas líneas y no redistribuye el texto.

  2. fmt, "formateador de texto simple", que a menudo también se instala en los sistemas Unix de forma predeterminada y un poco más inteligente que foldcuando se trata de refluir párrafos.

  3. par, " filtro para reformatear párrafos ", que tiene capacidades adicionales para detectar prefijos y sufijos de párrafo (como un texto con un cuadro ASCII alrededor, o comentarios en un poco de código fuente), y maneja la sangría y las sangrías colgantes un poco mejor que fmt.

Kusalananda
fuente
0

Usando gensub, para obtener foldsemántica, podría ejecutar algo en la línea de

awk '{printf gensub("(.{0,72})","\\1\n","g")}' 
JJoao
fuente