Sostituisci la stringa in un enorme file di testo (una riga da 70 GB)


126

Ho un enorme (70 GB), una riga , file di testo e voglio sostituire una stringa (token) in esso. Voglio sostituire il token <unk>, con un altro token fittizio ( problema con i guanti ).

Ho provato sed:

sed 's/<unk>/<raw_unk>/g' < corpus.txt > corpus.txt.new

ma il file di output corpus.txt.newha zero byte!

Ho anche provato a usare perl:

perl -pe 's/<unk>/<raw_unk>/g' < corpus.txt > corpus.txt.new

ma ho riscontrato un errore di memoria esaurita.

Per file più piccoli, funzionano entrambi i comandi precedenti.

Come posso sostituire una stringa è un tale file? Questa è una domanda correlata, ma nessuna delle risposte ha funzionato per me.

Modifica : che ne dici di dividere il file in blocchi di 10 GB (o altro) ciascuno e applicarlo sedsu ognuno di essi e poi unirli con cat? Ha senso? C'è una soluzione più elegante?


come ha notato @Gilles, riesci a rilevare alcuni caratteri ripetuti che potrebbero fungere da delimitatore personalizzato nella tua singola grande linea?
RomanPerekhrest,

Sto pensando che uno strumento che può solo cercare e sostituire, ma non una regex più complessa, sarebbe più veloce. Inoltre, non trarrebbe vantaggio dal fare una linea alla volta, quindi non soffocerebbe su questo file. Sfortunatamente non ho idea dell'esistenza di un tale strumento, anche se non sarebbe difficile da scrivere. Se è una tantum, la sostituzione con caratteri di nuova riga come in una delle risposte sarebbe probabilmente la più semplice.
ctrl-alt-delor,

Il tuo file contiene qualcosa di diverso da ASCII? In tal caso, è possibile omettere tutta la gestione degli Unicode e elaborare i byte non elaborati.
Patrick Bucher,

Sono d'accordo con @PatrickButcher Guarda un'immagine più grande. Oltre all'immediata necessità di sostituire questo testo, per cos'altro dovrebbe essere usato questo file? Se è un registro di qualche tipo, nessuno sarà in grado di lavorarci efficacemente. Se si tratta di un file di dati utilizzato da alcune app, tale app dovrebbe avere la responsabilità di conservare i dati in quel file.
Thomas Carlisle,

2
È possibile utilizzare splitcon l' -bopzione che definisce le dimensioni dei file di blocchi in byte. Elaborare ciascuno a sua volta usando sede riassemblare. Esiste il rischio che <unk>possa essere diviso in due file e non verrà trovato ...
Vladislavs Dovgalecs,

Risposte:


106

I soliti strumenti di elaborazione del testo non sono progettati per gestire linee che non rientrano nella RAM. Tendono a funzionare leggendo un record (una riga), manipolandolo e producendo il risultato, quindi procedendo al record successivo (riga).

Se c'è un carattere ASCII che appare frequentemente nel file e non appare in <unk>o <raw_unk>, allora puoi usarlo come separatore del record. Poiché la maggior parte degli strumenti non consente separatori di record personalizzati, scambia tra quel personaggio e le nuove righe. trelabora byte, non righe, quindi non si preoccupa di alcuna dimensione del record. Supponendo che funzioni ;:

<corpus.txt tr '\n;' ';\n' |
sed 's/<unk>/<raw_unk>/g' |
tr '\n;' ';\n' >corpus.txt.new

Puoi anche ancorare il primo carattere del testo che stai cercando, supponendo che non sia ripetuto nel testo di ricerca e appaia abbastanza frequentemente. Se il file può iniziare con unk>, modifica il comando sed in sed '2,$ s/…per evitare una corrispondenza spuria.

<corpus.txt tr '\n<' '<\n' |
sed 's/^unk>/raw_unk>/g' |
tr '\n<' '<\n' >corpus.txt.new

In alternativa, usa l'ultimo carattere.

<corpus.txt tr '\n>' '>\n' |
sed 's/<unk$/<raw_unk/g' |
tr '\n>' '>\n' >corpus.txt.new

Si noti che questa tecnica presuppone che sed operi senza interruzioni su un file che non termina con una nuova riga, ovvero che elabora l'ultima riga parziale senza troncarla e senza aggiungere una nuova riga finale. Funziona con GNU sed. Se riesci a scegliere l'ultimo carattere del file come separatore del record, eviterai qualsiasi problema di portabilità.


8
Non ho un file del genere con cui provare, ma in Awk puoi specificare "Separatore record" e "Separatore record di output". Quindi supponendo che tu abbia una discreta quantità di virgole nel tuo file, è possibile che tu possa risolverlo con: awk -v RS=, -v ORS=, '{gsub(/<unk>/, "<raw_unk>"); print}' No?
Wildcard il

4
@Wildcard Sì, questa è un'altra soluzione. Awk tende ad essere più lento di sed, tuttavia è per questo che non lo offro come soluzione preferita per un file di grandi dimensioni.
Gilles,

È possibile impostare il separatore di record in Perl con l'opzione della riga di comando -0e il valore ottale di un carattere, oppure all'interno dello script può essere impostato con una variabile speciale$/
beasy

@Gilles: Ma usando awkevitare di passare il flusso due volte a tr. Quindi sarebbe ancora più lento?
user285259

2
@ user285259 In genere no. trè molto veloce e il tubo può anche essere parallelizzato.
Gilles

110

Per un file così grande, una possibilità è Flex. Lascia che unk.lsia:

%%
\<unk\>     printf("<raw_unk>");  
%%

Quindi compilare ed eseguire:

$ flex -o unk.c  unk.l
$ cc -o unk -O2 unk.c -lfl
$ unk < corpus.txt > corpus.txt.new

5
makeha delle regole predefinite per questo, invece di flex / cc puoi aggiungere una %option maincome prima riga di unk.l e poi solo make unk. Uso più o meno riflessivamente %option main 8bit faste ho export CFLAGS='-march=native -pipe -Os'nel mio .bashrc.
jthill,

1
@undercat: se non fosse fuori tema, potrei mostrarti un numero di applicazioni front-end non compilatore, dalla risoluzione del problema del livello dell'acqua all'analisi dell'input per scopi speciali. È incredibile cosa puoi farci, se pensi un po 'fuori dagli schemi :-)
jamesqf

@jthill, grazie: %option main+ make+ opzionalmente CFLAGSsono un bel trucco !! È -march=nativeil comportamento predefinito?
JJoao,

1
@jamesqf come hai detto - sarà difficile fare una domanda sull'argomento - ma mi piacerebbe vederlo anche
Steven Penny

1
@jamesqf Un mio professore di uni ha usato il flex per costruire uno strumento che riconosceva i tipi di tessuto per una fabbrica! Che ne dici di chiedere qualcosa del tipo: "flex sembra uno strumento molto potente, ma è improbabile che stia scrivendo compilatori / parser - ci sono altri casi d'uso per flex?"
Paul Evans,

40

Quindi non hai abbastanza memoria fisica (RAM) per contenere l'intero file in una volta, ma su un sistema a 64 bit hai abbastanza spazio di indirizzi virtuali per mappare l'intero file. I mapping virtuali possono essere utili come un semplice hack in casi come questo.

Le operazioni necessarie sono tutte incluse in Python. Esistono diverse sottigliezze fastidiose, ma evita di dover scrivere il codice C. In particolare, è necessario prestare attenzione per evitare di copiare il file in memoria, il che annullerebbe completamente il punto. Tra i lati positivi, si ottiene gratuitamente la segnalazione degli errori ("eccezioni" di Python :) :).

#!/usr/bin/python3
# This script takes input from stdin
# (but it must be a regular file, to support mapping it),
# and writes the result to stdout.

search = b'<unk>'
replace = b'<raw_unk>'


import sys
import os
import mmap

# sys.stdout requires str, but we want to write bytes
out_bytes = sys.stdout.buffer

mem = mmap.mmap(sys.stdin.fileno(), 0, access=mmap.ACCESS_READ)
i = mem.find(search)
if i < 0:
    sys.exit("Search string not found")

# mmap object subscripts to bytes (making a copy)
# memoryview object subscripts to a memoryview object
# (it implements the buffer protocol).
view = memoryview(mem)

out_bytes.write(view[:i])
out_bytes.write(replace)
out_bytes.write(view[i+len(search):])

Se il mio sistema ha circa 4 GB di memoria libera conseguente da 8 GB, mem = mmap.mmap (sys.stdin.fileno (), 0, access = mmap.ACCESS_READ) significa che posiziona i dati in quello spazio? O sarebbe molto più basso (1 gb?)>
Rahul il

1
@Rahul "Quindi non hai abbastanza RAM, ma su un sistema a 64 bit hai abbastanza spazio di indirizzi virtuali per mappare l'intero file." È impaginato dentro e fuori dall'ariete fisico su richiesta (o mancanza di ciò). Questo programma dovrebbe funzionare senza richiedere grandi quantità di RAM fisica. I sistemi a 64 bit hanno molto più spazio di indirizzi virtuali rispetto al massimo RAM fisico. Inoltre ogni processo in esecuzione ha il proprio spazio di indirizzi virtuale. Ciò significa che il sistema nel suo complesso esaurire lo spazio degli indirizzi virtuali non è una cosa, non è un concetto valido.
Fontejedi

4
@Rahul sì! python mmap.mmap () è un wrapper abbastanza sottile attorno alla funzione C mmap (). E mmap () è lo stesso meccanismo utilizzato per eseguire eseguibili e codice da librerie condivise.
Fontejedi

2
@jamesqf Potrei sbagliarmi, ma penso che sia solo una scelta personale. Poiché le perdite di prestazioni sarebbero trascurabili (perché, come ha detto, la funzione effettiva chiama la funzione c), lo spreco ambientale è molto basso, poiché non si verificano altre cose nel mezzo. C sarebbe stato migliore, ma questa soluzione non mirava all'ottimizzazione, ma solo per risolvere il problema più grande e difficile di 70 GB.
Rahul,

1
In generale, scrivere in Python è più compatto. In questo caso si è scoperto che ci sono un paio di dettagli nella versione Python, e la versione C potrebbe essere stata più bella da scrivere. (Anche se non è così semplice se searchpuò contenere un carattere NUL. E noto che qui l'altra versione C non supporta i caratteri NUL replace.). Sei il benvenuto a derivare la versione C a fini di confronto. Tuttavia, ricorda che la mia versione include la segnalazione di errori di base per le operazioni che esegue. La versione C sarebbe almeno più fastidiosa da leggere IMO, quando è inclusa la segnalazione degli errori.
sourcejedi

16

C'è replaceun'utilità nel pacchetto mariadb-server / mysql-server. Sostituisce stringhe semplici (non espressioni regolari) e, a differenza di grep / sed / awk, replacenon si preoccupa di \ne \0. Il consumo di memoria è costante con qualsiasi file di input (circa 400kb sulla mia macchina).

Naturalmente non è necessario eseguire un server mysql per replacepoterlo utilizzare , è solo impacchettato in quel modo in Fedora. Altre distribuzioni / sistemi operativi potrebbero averlo impacchettato separatamente.


16

Penso che la versione C potrebbe funzionare molto meglio:

#include <stdio.h>
#include <string.h>

#define PAT_LEN 5

int main()
{
    /* note this is not a general solution. In particular the pattern
     * must not have a repeated sequence at the start, so <unk> is fine
     * but aardvark is not, because it starts with "a" repeated, and ababc
     * is not because it starts with "ab" repeated. */
    char pattern[] = "<unk>";          /* set PAT_LEN to length of this */
    char replacement[] = "<raw_unk>"; 
    int c;
    int i, j;

    for (i = 0; (c = getchar()) != EOF;) {
        if (c == pattern[i]) {
            i++;
            if (i == PAT_LEN) {
                printf("%s", replacement);
                i = 0;
            }
        } else {
            if (i > 0) {
                for (j = 0; j < i; j++) {
                    putchar(pattern[j]);
                }
                i = 0;
            }
            if (c == pattern[0]) {
                i = 1;
            } else {
                putchar(c);
            }
        }
    }
    /* TODO: fix up end of file if it ends with a part of pattern */
    return 0;
}

EDIT: modificato in base ai suggerimenti dei commenti. Corretto anche bug con il modello <<unk>.


2
puoi stampare (pattern [j]) invece di (buf [j]) (sono uguali a questo punto, quindi non hai bisogno di buffer
RiaD

3
anche il codice non funzionerà per la stringa "<" ideone.com/ncM2yy
RiaD

10
30 MB in 0,3 secondi? Sono solo 90 MB / secondo. memcpyla velocità (ovvero il collo di bottiglia della memoria) è simile a 12 GB / secondo su una recente CPU x86 (ad esempio Skylake). Anche con overhead di chiamata di sistema stdio +, per un file di 30 MB caldo nella cache del disco, mi aspetto forse 1 GB / secondo per un'implementazione efficiente. È stata compilata con l'ottimizzazione disabilitata o l'I / O con un carattere alla volta è davvero così lento? getchar_unlocked/ putchar_unlockedpotrebbe aiutare, ma sicuramente meglio leggere / scrivere in blocchi di forse 128 kB (metà della dimensione della cache L2 sulla maggior parte delle CPU x86, quindi colpisci principalmente in L2 mentre esegui il ciclo dopo la lettura)
Peter Cordes il

2
dalla cima della mia testa, getchar e putchar sono lenti.
Rui F Ribeiro,

3
Il fixprogramma "<<unk>"continua a non funzionare se patterninizia con una sequenza ripetuta di caratteri (ovvero non funzionerebbe se si stesse cercando di sostituire aardvark con zebra e si avesse input di aaardvak o si stesse cercando di sostituire ababc e aveva input di abababc). In generale, non puoi andare avanti in base al numero di caratteri che hai letto a meno che tu non sappia che non esiste alcuna possibilità di iniziare una partita tra i personaggi che hai letto.
Icaro, il

14

GNU greppuò mostrare l'offset delle corrispondenze nei file "binari", senza dover leggere intere righe in memoria. È quindi possibile utilizzare ddper leggere fino a questo offset, saltare la corrispondenza, quindi continuare a copiare dal file.

file=...
newfile=...
replace='<raw_unk>'
grep -o -b -a -F '<unk>' <"$file" |
(   pos=0
    while IFS=$IFS: read offset pattern
    do size=${#pattern}
       let skip=offset-pos
       let big=skip/1048576
       let skip=skip-big*1048576
       dd bs=1048576 count=$big <&3
       dd bs=1 count=$skip <&3
       dd bs=1 count=$size of=/dev/null <&3
       printf "%s" "$replace"
       let pos=offset+size
    done
    cat <&3
) 3<"$file" >"$newfile"

Per velocità, ho diviso ddin una lettura grande di 1048576 blocchi e una lettura più piccola di 1 byte alla volta, ma questa operazione sarà ancora un po 'lenta su un file così grande. L' grepoutput è, ad esempio, 13977:<unk>e questo è diviso sui due punti dalla lettura in variabili offsete pattern. Dobbiamo tenere traccia posdi quanti byte sono già stati copiati dal file.


11

Ecco un'altra riga di comando UNIX che potrebbe funzionare meglio di altre opzioni, perché puoi "cercare" una "dimensione del blocco" che funzioni bene. Perché questo sia robusto devi sapere che hai almeno uno spazio in ogni X caratteri, dove X è la tua "dimensione del blocco" arbitraria. Nell'esempio seguente ho scelto una "dimensione del blocco" di 1024 caratteri.

fold -w 1024 -s corpus.txt | sed 's/<unk>/<raw_unk>/g' | tr '/n' '/0'

Qui, fold prenderà fino a 1024 byte, ma la -s si assicura che si spezzi su uno spazio se ce n'è almeno uno dall'ultima interruzione.

Il comando sed è tuo e fa quello che ti aspetti.

Quindi il comando tr "aprirà" il file convertendo le nuove righe che sono state reinserite in nulla.

Dovresti provare a provare blocchi di dimensioni maggiori per vedere se funziona più velocemente. Invece di 1024, potresti provare 10240 e 102400 e 1048576 per l'opzione -w di fold.

Ecco un esempio suddiviso per ogni passaggio che converte tutte le N in minuscolo:

[root@alpha ~]# cat mailtest.txt
test XJS C4JD QADN1 NSBN3 2IDNEN GTUBE STANDARD ANTI UBE-TEST EMAIL*C.34X test

[root@alpha ~]# fold -w 20 -s mailtest.txt
test XJS C4JD QADN1
NSBN3 2IDNEN GTUBE
STANDARD ANTI
UBE-TEST
EMAIL*C.34X test

[root@alpha ~]# fold -w 20 -s mailtest.txt | sed 's/N/n/g'
test XJS C4JD QADn1
nSBn3 2IDnEn GTUBE
STAnDARD AnTI
UBE-TEST
EMAIL*C.34X test

[root@alpha ~]# fold -w 20 -s mailtest.txt | sed 's/N/n/g' | tr '\n' '\0'
test XJS C4JD QADn1 nSBn3 2IDnEn GTUBE STAnDARD AnTI UBE-TEST EMAIL*C.34X test

Dovrai aggiungere una nuova riga alla fine del file se ne ha uno, perché il comando tr lo rimuoverà.


1
Come assicurarsi di non interrompere il modello nei casi limite in cui non è disponibile spazio sufficiente?
rackandboneman

1
Come detto, per essere robusto, è necessario che ci sia almeno uno spazio ogni X caratteri. Puoi fare quell'analisi abbastanza facilmente, con qualsiasi dimensione di blocco tu scelga: fold -w X mailtest.txt | grep -v "" | wc -l Il numero che restituisce è il numero di linee piegate con potenziali casi limite. Se è zero, la soluzione è garantita per funzionare.
alfreema,

10

utilizzando perl

Gestire i propri buffer

È possibile utilizzare IO::Handle's setvbufper gestire i buffer predefiniti oppure è possibile gestire i propri buffer con sysreade syswrite. Controllare perldoc -f sysreade perldoc -f syswriteper ulteriori informazioni, essenzialmente saltano io bufferato.

Qui rotoliamo il nostro buffer IO, ma lo facciamo manualmente e arbitrariamente su 1024 byte. Apriamo anche il file per RW, quindi facciamo tutto sullo stesso FH in una volta.

use strict;
use warnings;
use Fcntl qw(:flock O_RDWR);
use autodie;
use bytes;

use constant CHUNK_SIZE => 1024 * 32;

sysopen my $fh, 'file', O_RDWR;
flock($fh, LOCK_EX);

my $chunk = 1;
while ( sysread $fh, my $bytes, CHUNK_SIZE * $chunk ) {
  if ( $bytes =~ s/<unk>/<raw_unk>/g ) {
    seek( $fh, ($chunk-1)* CHUNK_SIZE, 0 );
    syswrite( $fh, $bytes, 1024);
    seek( $fh, $chunk * CHUNK_SIZE, 0 );
  }
  $chunk++;
}

Se hai intenzione di seguire questa strada

  1. Assicurarsi <unk>e avere <raw_unk>la stessa dimensione di byte.
  2. Potresti voler assicurarti che il nostro metodo bufferizzato non CHUNKSIZEsuperi il limite, se stai sostituendo più di 1 byte.

2
Cosa succede se <unk>cade su un confine tra blocchi?
liori,

8

Potresti provare bbe ( editor di blocchi binari ), un " sedper file binari".

Ho avuto un buon successo usandolo su un file di testo da 7 EOLGB senza caratteri, sostituendo più occorrenze di una stringa con una di diversa lunghezza. Senza tentare di ottimizzare, ha prodotto un throughput di elaborazione medio di> 50 MB / s.


5

Con perl, potresti lavorare con record a lunghezza fissa come:

perl -pe 'BEGIN{$/=\1e8}
          s/<unk>/<raw_unk>/g' < corpus.txt > corpus.txt.new

E spero che non ci saranno <unk>spanning su due di quei record da 100 MB.


Stavo anche pensando a questo metodo, ma usando il while read -N 1000 chunk;(il 1000scelto come esempio). La soluzione per <unk>, suddivisa tra i blocchi, è costituita da due passaggi nel file: il primo con i blocchi da 100 MB e il secondo con i blocchi da "100 MB + 5 byte". Ma non è una soluzione ottimale nel caso del file da 70 GB.
MiniMax,

3
Non hai nemmeno bisogno di due passaggi. Leggi il blocco A. Se non EOF, leggi il blocco B. Cerca / Sostituisci in A + B. A: = B. Loop. La complessità sta assicurando che non si sostituisca all'interno della sostituzione.
roaima,

@MiniMax, quel secondo passaggio non sarebbe necessariamente di aiuto in quanto il primo passaggio avrebbe aggiunto 5 byte per ogni occorrenza di <unk>.
Stéphane Chazelas,

1
@roaima, sì, sarebbe una soluzione molto più complessa. Qui è un approccio semplice che è solo altamente probabile (supponendo che le <unk>occorrenze siano molto lontane, se non, usano $/ = ">"e s/<unk>\z/<raw_unk>/g) di essere corrette.
Stéphane Chazelas,

5

Ecco un piccolo programma Go che esegue l'attività ( unk.go):

package main

import (
    "bufio"
    "fmt"
    "log"
    "os"
)

func main() {
    const (
        pattern     = "<unk>"
        replacement = "<raw_unk>"
    )
    var match int
    var char rune
    scanner := bufio.NewScanner(os.Stdin)
    scanner.Split(bufio.ScanRunes)
    for scanner.Scan() {
        char = rune(scanner.Text()[0])
        if char == []rune(pattern)[match] {
            match++
            if match == len(pattern) {
                fmt.Print(replacement)
                match = 0
            }
        } else {
            if match > 0 {
                fmt.Print(string(pattern[:match]))
                match = 0
            }
            if char == rune(pattern[0]) {
                match = 1
            } else {
                fmt.Print(string(char))
            }
        }
    }
    if err := scanner.Err(); err != nil {
        log.Fatal(err)
    }
}

Costruiscilo go build unk.goed eseguilo come ./unk <input >output.

MODIFICARE:

Siamo spiacenti, non ho letto che tutto è in una riga, quindi ho provato a leggere il file carattere per carattere ora.

EDIT II:

Applicata la stessa correzione del programma C.


1
questo evita di leggere l'intero file in memoria?
cat

1
Legge il carattere del file per carattere e non contiene mai l' intero file in memoria, solo singoli caratteri.
Patrick Bucher,

1
scanner.Split(bufio.ScanRunes)fa la magia.
Patrick Bucher,

Verificare anche go doc bufio.MaxScanTokenSizela dimensione del buffer predefinita.
Patrick Bucher,

Come il tuo Cprogramma, questo non funziona per sostituire aardvark con zebra con un input di aaardvark.
Icaro, il

1

Questo potrebbe essere eccessivo per un file da 70 GB e una semplice ricerca e sostituzione, ma il framework Hadoop MapReduce risolverà il tuo problema in questo momento senza alcun costo (scegli l'opzione 'Nodo singolo' quando lo configuri per eseguirlo localmente) - e può essere ridimensionato a capacità infinita in futuro senza la necessità di modificare il codice.

Il tutorial ufficiale su https://hadoop.apache.org/docs/stable/hadoop-mapreduce-client/hadoop-mapreduce-client-core/MapReduceTutorial.html utilizza Java (estremamente semplice) ma puoi trovare librerie client per Perl o qualunque lingua tu voglia usare.

Quindi, se in seguito ti accorgi che stai eseguendo operazioni più complesse su file di testo da 7000 GB e che devi farlo 100 volte al giorno, puoi distribuire il carico di lavoro su più nodi forniti o forniti automaticamente da un cloud- cluster Hadoop basato.


1
si si lo è. "Non usare Hadoop - i tuoi dati non sono così grandi" . Questo è un problema IO di streaming molto semplice.
sourcejedi

0

Tutti i suggerimenti precedenti richiedono la lettura dell'intero file e la scrittura dell'intero file. Questo non solo richiede molto tempo, ma richiede anche 70 GB di spazio libero.

1) Se avessi compreso correttamente il tuo caso specifico, sarebbe accettabile sostituire con qualche altra stringa della stessa lunghezza?

2a) Ci sono più ricorrenze? 2b) Se sì, sai quanti?

Sono sicuro che hai già risolto il problema di quest'anno e vorrei sapere quale soluzione hai usato.

Proporrei una soluzione (molto probabilmente in C) che legga i BLOCCHI del file alla ricerca di ciascuno della stringa tenendo conto del possibile passaggio di blocchi. Una volta trovato, sostituire la stringa con la lunghezza SAME alternata e scrivere solo quel BLOCK. Continuando per il numero noto di occorrenze o fino alla fine del file. Ciò richiederebbe solo il numero di occorrenze e al massimo il doppio (se ogni occorrenza fosse divisa tra 2 blocchi). Ciò non richiederebbe ulteriore spazio!


-1

Se abbiamo un importo minimo di <unk>(come previsto dalla legge di Zipf),

awk -v RS="<unk>" -v ORS="<raw_unk>" 1

1
No. sedlegge una riga alla volta nella memoria, indipendentemente. Non sarà in grado di adattarsi a questa linea.
Kusalananda

1
Non riesco a trovare alcuna documentazione che dica altro che GNU sednon eseguirà il buffering di input / output quando si utilizza questo flag. Non riesco a vedere che leggerà righe parziali.
Kusalananda
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.