macosawk

How to create multiple files from a single file using separators?


I am trying to generate multiple files from a .txt file with separators. In this case, the column separator is | and the record separator is: .

Each name value only appear once in the input.

This is the code I'm trying:

awk -F'║', -vOFS=, -vc=1 '
NR == 1 {
    for (i=1; i<NF; i++) {
        if ($i != "") {
            g[c]=i;
            f[c++]=$i
        }
    }
}
NR>2 {
    for (i=1; i < c; i++) {
        print $1,$2, $g[i] > "output_"f[i]".tex"
    }
}' biennalis.txt

The content of biennalis.txt is something like this:

name|content
║Is-id27-ref06-01-13-1914|El año de la muerte del rey Ozías vi al Señor sentado en un trono excelso y elevado, y sus haldas llenaban el templo. Unos serafines se mantenían erguidos por encima de él; cada uno tenía seis alas: con un par se cubrían la faz, con otro par se cubrían los pies, y con el otro par aleteaban, y se gritaban el uno al otro:

 \textquote{Santo, santo, santo, el Señor de los ejércitos: llena está toda la tierra de su gloria.}.

 Se conmovieron los quicios y los dinteles a la voz de los que clamaban, y la casa se llenó de humo.

 Yo dije:

 \textquote{¡Ay de mí, que estoy perdido, pues soy un hombre de labios impuros, y entre un pueblo de labios impuros habito: que al rey el Señor de los ejércitos han visto mis ojos!}

 Entonces voló hacia mí uno de los serafines con una brasa en la mano, que con las tenazas había tomado de sobre el altar, y tocó mi boca y dijo:

 \textquote{He aquí que esto ha tocado tus labios: se ha retirado tu culpa, tu pecado está expiado.}

 Y percibí la voz del Señor que decía:

 \textquote{¿A quién enviaré? ¿y quién irá de parte nuestra}?

 Yo contesté:

 \textquote{Heme aquí: envíame.}

 Dijo:

 \textquote{Ve y di a ese pueblo: \textquote{Escuchad bien, pero no entendáis, ved bien, pero no comprendáis.} Engorda el corazón de ese pueblo, hazle duro de oídos, y pégale los ojos, no sea que vea con sus ojos y oiga con sus oídos, y entienda con su corazón, y se convierta y se le cure.}

 Yo pregunté:

 \textquote{¿Hasta dónde, Señor?}

 Y él me contestó:

 \textquote{Hasta que se vacíen las ciudades y queden sin habitantes, las casas sin hombres, la campiña desolada, y haya alejado el Señor a las gentes, y cunda el abandono dentro del país. Aun el décimo que quede en él volverá a ser devastado como la encina o el roble, en cuya tala queda un tocón. Este tocón será semilla santa.}


║Is-id27-ref01-01-18-0045|Visión de Isaías, hijo de Amós, acerca de Judá y de Jerusalén, en tiempos de Ozías, Jotán, Ajaz y Ezequías, reyes de Judá.

 Oíd, cielos, escucha tierra, que habla el Señor: \textquote{Hijos he criado y educado, y ellos se han rebelado contra mí.

 El buey conoce a su amo, y el asno el pesebre de su dueño; Israel no me conoce, mi pueblo no comprende}.

 ¡Ay, gente pecadora, pueblo cargado de culpas, raza malvada, hijos corrompidos! Han abandonado al Señor, han despreciado al santo de Israel, le han vuelto la espalda.

The end result I expect is separate files, whose name is the content of the first column and the content is what is in the second column:

Is-id27-ref06-01-13-1914.tex

El año de la muerte del rey Ozías vi al Señor sentado en un trono excelso y elevado, y sus haldas llenaban el templo. Unos serafines se mantenían erguidos por encima de él; cada uno tenía seis alas: con un par se cubrían la faz, con otro par se cubrían los pies, y con el otro par aleteaban, y se gritaban el uno al otro:

 \textquote{Santo, santo, santo, el Señor de los ejércitos: llena está toda la tierra de su gloria.}.

...

Is-id27-ref01-01-18-0045.tex

Visión de Isaías, hijo de Amós, acerca de Judá y de Jerusalén, en tiempos de Ozías, Jotán, Ajaz y Ezequías, reyes de Judá.

 Oíd, cielos, escucha tierra, que habla el Señor: \textquote{Hijos he criado y educado, y ellos se han rebelado contra mí.

...

Etc ...

The error when executing the command is as follows:

awk: syntax error at source line 10
    context is
        print $1,$2, $g[i] > >>>  "output_"f <<< [i]".tex"
awk: illegal statement at source line 10

Solution

  • An unparenthesized expression on the right side of input or output redirection is undefined behavior and so different awks will do different things with it, some will do what you want while others will fail as you're currently seeing. Change this:

    print $1,$2, $g[i] > "output_"f[i]".tex"
    

    to this:

    print $1,$2, $g[i] > ("output_"f[i]".tex")
    

    to solve that specific problem.

    The next problem you may encounter is that you're not closing output files as you go and so you may run into a limit on how many files a process can have open at once. To fix that change your loop to:

    for (i=1; i < c; i++) {
        out = "output_"f[i]".tex"
        if ( !seen[out]++ ) {
            printf "" > out
        }
        print $1,$2, $g[i] >> out
        close(out)
    }
    

    The if statement with seen[] is to ensure the script empties any existing output file the first time your script writes to it - if you handle that outside of the script then you can remove that if statement.

    Given the information you added in comments and assuming each name field is unique, it now sounds like this is what you need overall, using any awk and regardless of whether or not or |s appear elsewhere in your input:

    $ cat tst.awk
    sub(/^║/,"") {
        close(out)
        pos = index($0,"|")
        out = "output_" substr($0,1,pos-1) ".tex"
        $0  = substr($0,pos+1)
    }
    NR > 1 { print > out }
    

    $ awk -f tst.awk biennalis.txt
    
    $ cat output_Is-id27-ref06-01-13-1914.tex
    El año de la muerte del rey Ozías vi al Señor sentado en un trono excelso y elevado, y sus haldas llenaban el templo. Unos serafines se mantenían erguidos por encima de él; cada uno tenía seis alas: con un par se cubrían la faz, con otro par se cubrían los pies, y con el otro par aleteaban, y se gritaban el uno al otro:
    
     \textquote{Santo, santo, santo, el Señor de los ejércitos: llena está toda la tierra de su gloria.}.
    
     Se conmovieron los quicios y los dinteles a la voz de los que clamaban, y la casa se llenó de humo.
    
     Yo dije:
    
     \textquote{¡Ay de mí, que estoy perdido, pues soy un hombre de labios impuros, y entre un pueblo de labios impuros habito: que al rey el Señor de los ejércitos han visto mis ojos!}
    
     Entonces voló hacia mí uno de los serafines con una brasa en la mano, que con las tenazas había tomado de sobre el altar, y tocó mi boca y dijo:
    
     \textquote{He aquí que esto ha tocado tus labios: se ha retirado tu culpa, tu pecado está expiado.}
    
     Y percibí la voz del Señor que decía:
    
     \textquote{¿A quién enviaré? ¿y quién irá de parte nuestra}?
    
     Yo contesté:
    
     \textquote{Heme aquí: envíame.}
    
     Dijo:
    
     \textquote{Ve y di a ese pueblo: \textquote{Escuchad bien, pero no entendáis, ved bien, pero no comprendáis.} Engorda el corazón de ese pueblo, hazle duro de oídos, y pégale los ojos, no sea que vea con sus ojos y oiga con sus oídos, y entienda con su corazón, y se convierta y se le cure.}
    
     Yo pregunté:
    
     \textquote{¿Hasta dónde, Señor?}
    
     Y él me contestó:
    
     \textquote{Hasta que se vacíen las ciudades y queden sin habitantes, las casas sin hombres, la campiña desolada, y haya alejado el Señor a las gentes, y cunda el abandono dentro del país. Aun el décimo que quede en él volverá a ser devastado como la encina o el roble, en cuya tala queda un tocón. Este tocón será semilla santa.}
    
    $ cat output_Is-id27-ref01-01-18-0045.tex
    Visión de Isaías, hijo de Amós, acerca de Judá y de Jerusalén, en tiempos de Ozías, Jotán, Ajaz y Ezequías, reyes de Judá.
    
     Oíd, cielos, escucha tierra, que habla el Señor: \textquote{Hijos he criado y educado, y ellos se han rebelado contra mí.
    
     El buey conoce a su amo, y el asno el pesebre de su dueño; Israel no me conoce, mi pueblo no comprende}.
    
     ¡Ay, gente pecadora, pueblo cargado de culpas, raza malvada, hijos corrompidos! Han abandonado al Señor, han despreciado al santo de Israel, le han vuelto la espalda.