Come posso sostituire una newline (\ n) usando sed?


1371

Come posso sostituire una newline (" \n") con uno spazio (" ") usando il sedcomando?

Ho provato senza successo:

sed 's#\n# #g' file
sed 's#^$# #g' file

Come lo aggiusto?


27
trè solo lo strumento giusto per il lavoro se si sostituisce un singolo carattere per un singolo carattere, mentre l'esempio sopra mostra sostituire newline con uno spazio .. Quindi nell'esempio sopra, tr potrebbe funzionare .. Ma sarebbe limitare in seguito.
Angry 84

9
trnello strumento giusto per il lavoro perché l'interrogante voleva sostituire ogni nuova riga con uno spazio, come mostrato nel suo esempio. La sostituzione di newline è unicamente arcana sedma facilmente realizzabile tr. Questa è una domanda comune L'esecuzione di sostituzioni regex non è fatta da trma da sed, che sarebbe lo strumento giusto ... per una domanda diversa.
Mike S,

3
"tr" può anche semplicemente cancellare la nuova riga `tr -d '\ n'` tuttavia potresti anche voler cancellare i ritorni per essere più universale `tr -d '\ 012 \ 015'`.
Anthony

2
ATTENZIONE: "tr" agisce in modo diverso rispetto a una gamma di caratteri tra Linux e le macchine Solaris precedenti (EG sol5.8). Ad esempio: `tr -d 'az'` e `tr -d '[az]'`. Per questo ti consiglio di usare "sed" che non ha questa differenza.
Anthony

2
@MikeS Grazie per la risposta. Segui tr '\012' ' 'con un echo. In caso contrario, viene eliminato anche l'ultimo avanzamento riga nel file. tr '\012' ' ' < filename; echofa il trucco.
Bernie Reiter,

Risposte:


1514

Usa questa soluzione con GNU sed:

sed ':a;N;$!ba;s/\n/ /g' file

Questo leggerà l'intero file in un ciclo, quindi sostituirà le nuove righe con uno spazio.

Spiegazione:

  1. Crea un'etichetta tramite :a.
  2. Aggiunge la riga corrente e successiva allo spazio del modello tramite N.
  3. Se siamo prima dell'ultima riga, passa all'etichetta creata $!ba( $!significa non farlo sull'ultima riga poiché dovrebbe esserci un'ultima riga finale).
  4. Infine, la sostituzione sostituisce ogni nuova riga con uno spazio nello spazio del modello (che è l'intero file).

Ecco una sintassi compatibile multipiattaforma che funziona con BSD e OS X sed(come da commento su @Benjie ):

sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/ /g' file

Come puoi vedere, l'utilizzo sedper questo problema altrimenti semplice è problematico. Per una soluzione più semplice e adeguata vedi questa risposta .


45
@Arjan e Masi: OS X usa BSD sedpiuttosto che GNU sed, quindi potrebbero esserci delle differenze sottili (e alcune non così sottili) nelle due. Questo è un dolore costante se lavori su entrambe le macchine OS X e * nix. Di solito installo GNU coreutilse findutilssu OS X e ignoro le versioni di BSD.
Telemaco,

50
Non :aè un registro, è un'etichetta di filiale. È un obiettivo per il bcomando * che funziona come "goto". Chiamandolo un registro implica che è possibile creare posizioni di archiviazione. Esistono solo due "registri"; uno è chiamato "spazio di attesa" che lo script non sta usando e l'altro è chiamato "spazio modello". Il Ncomando aggiunge una nuova riga e la riga successiva del file di input allo spazio modello. [* Puoi avere più etichette e bcomandi. Se hai un bcomando senza un'etichetta char aggiunta ad esso, si ramifica alla fine dello script per leggere la riga successiva e ripetere il ciclo.]
Messo in pausa fino a nuovo avviso.

108
Puoi eseguire questa multipiattaforma (cioè su Mac OS X) eseguendo separatamente i comandi anziché separarli con punti e virgola: sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/ /g'
Benjie,

74
Perché nessuno commenta cosa sia un casino stupido (non la risposta stessa, ma il programma per il quale la risposta proposta è la migliore soluzione a un problema molto semplice). Sed sembra un'auto che di solito funziona bene, ma se vuoi guidare in una specifica strada vicina, l'unico modo è sollevare l'auto con un elicottero.
Ark-kun,

12
Forza gente - 261 voti per una soluzione folle e incomprensibile che non funziona ???? sed è uno strumento eccellente per semplici sostituzioni su una sola riga, per qualsiasi altra cosa basta usare awk. Buon dolore ....
Ed Morton,

1711

sedè inteso per essere utilizzato sull'input basato su linea. Anche se può fare quello che ti serve.


Un'opzione migliore qui è usare il trcomando come segue:

tr '\n' ' ' < input_filename

o rimuovi completamente i caratteri di nuova riga:

tr -d '\n' < input.txt > output.txt

o se hai la versione GNU (con le sue lunghe opzioni)

tr --delete '\n' < input.txt > output.txt

88
Sed è basato sulla linea, quindi è difficile afferrare le nuove linee.
Alexander Gladysh,

191
sed lavora su un "flusso" di input, ma lo comprende in blocchi delimitati da newline. È uno strumento unix, il che significa che fa una cosa molto bene. L'unica cosa è "lavorare su un file in linea". Farlo fare qualcos'altro sarà difficile e rischia di essere difettoso. La morale della storia è: scegli lo strumento giusto. Molte delle tue domande sembrano prendere la forma "Come posso fare questo strumento fare qualcosa che non è mai stato pensato di fare?" Quelle domande sono interessanti, ma se sorgono nel risolvere un problema reale, probabilmente stai sbagliando.
dmckee --- ex gattino moderatore

7
@JBBrown trè una gemma spesso trascurata per la costruzione di condotte.
dmckee --- ex-moderatore gattino

70
tr è fantastico, ma puoi sostituire solo le nuove righe con singoli caratteri. È necessario utilizzare uno strumento diverso se si desidera sostituire le nuove righe con una stringa
Eddy,

21
@Eddy - Ho usato tr per sostituire le nuove righe con un carattere che non appare nel testo (ho usato il backtick), quindi sed per sostituire il backtick con la stringa che volevo usare
rjohnston

494

Risposta veloce

sed ':a;N;$!ba;s/\n/ /g' file
  1. : a crea un'etichetta 'a'
  2. N aggiunge la riga successiva allo spazio del motivo
  3. $! se non l'ultima riga , ba branch (vai a) etichetta 'a'
  4. s sostituire , / \ n / regex per la nuova riga , / / con uno spazio , / g corrispondenza globale (quante più volte possibile)

sed passerà attraverso i passaggi da 1 a 3 fino a raggiungere l'ultima riga, facendo in modo che tutte le linee si adattino allo spazio del modello in cui sed sostituirà tutti i \ n caratteri


alternative

Tutte le alternative, a differenza di sed , non dovranno raggiungere l'ultima riga per iniziare il processo

con bash , lento

while read line; do printf "%s" "$line "; done < file

con velocità perl , sed- like

perl -p -e 's/\n/ /' file

con tr , più veloce di sed , può essere sostituito da un solo carattere

tr '\n' ' ' < file

con incolla , velocità tr- like, può sostituire solo con un carattere

paste -s -d ' ' file

con awk , tr -come velocità

awk 1 ORS=' ' file

Un'altra alternativa come "echo $ (<file)" è lenta, funziona solo su file di piccole dimensioni e deve elaborare l'intero file per iniziare il processo.


Risposta lunga dal FAQ FAQ 5.10

5.10. Perché non riesco ad abbinare o cancellare una nuova riga usando la
sequenza di escape \ n ? Perché non riesco ad abbinare 2 o più righe usando \ n?

La \ n non corrisponderà mai alla nuova riga alla fine della riga poiché la
nuova riga viene sempre rimossa prima che la riga venga posizionata nello
spazio del motivo. Per ottenere 2 o più linee nello spazio del pattern, usa
il comando 'N' o qualcosa di simile (come 'H; ...; g;').

Sed funziona in questo modo: sed legge una riga alla volta, taglia la
nuova riga finale, inserisce ciò che rimane nello spazio del modello in cui
lo script sed può indirizzarlo o modificarlo e quando
viene stampato lo spazio del modello , aggiunge una nuova riga allo stdout (o in un file). Se lo
spazio del motivo viene completamente o parzialmente cancellato con 'd' o 'D', in questi casi la
newline non viene aggiunta. Quindi, gli script piacciono

  sed 's/\n//' file       # to delete newlines from each line             
  sed 's/\n/foo\n/' file  # to add a word to the end of each line         

non funzionerà MAI, perché la nuova riga finale viene rimossa prima che
la linea venga inserita nello spazio modello. Per eseguire le attività di cui sopra,
utilizzare invece uno di questi script:

  tr -d '\n' < file              # use tr to delete newlines              
  sed ':a;N;$!ba;s/\n//g' file   # GNU sed to delete newlines             
  sed 's/$/ foo/' file           # add "foo" to end of each line          

Poiché versioni di sed diverse da GNU sed hanno limiti alle dimensioni del
pattern buffer, l'utilità 'tr' di Unix è da preferire qui.
Se l'ultima riga del file contiene una nuova riga, GNU sed aggiungerà
quella nuova riga all'output ma eliminerà tutte le altre, mentre tr
eliminerà tutte le nuove righe.

Per abbinare un blocco di due o più linee, ci sono 3 scelte di base:
(1) usa il comando 'N' per aggiungere la linea successiva allo spazio del modello;
(2) utilizzare il comando 'H' almeno due volte per aggiungere la linea corrente
allo spazio di attesa, quindi recuperare le linee dallo spazio di attesa
con x, g o G; oppure (3) utilizzare gli intervalli di indirizzi (vedere la sezione 3.3, sopra)
per far corrispondere le linee tra due indirizzi specificati.

Le scelte (1) e (2) inseriranno un \ n nello spazio del motivo, dove
può essere indirizzato come desiderato ('s / ABC \ nXYZ / alfabeto / g'). Un esempio
dell'uso di 'N' per cancellare un blocco di linee appare nella sezione 4.13
("Come posso cancellare un blocco di specifiche linee consecutive?"). Questo
esempio può essere modificato cambiando il comando delete in
qualcos'altro, come 'p' (stampa), 'i' (inserisci), 'c' (cambia), 'a' (aggiungi)
o 's' (sostituisci) .

Choice (3) non sarà mettere un \ n nello spazio modello, ma non
corrispondono a un blocco di righe consecutive, quindi potrebbe essere che non hai
nemmeno bisogno del \ n per trovare quello che stai cercando. Poiché GNU sed
versione 3.02.80 ora supporta questa sintassi:

  sed '/start/,+4d'  # to delete "start" plus the next 4 lines,           

oltre ai tradizionali indirizzi "/ da qui /, / a là / {...}"
, potrebbe essere possibile evitare l'uso di \ n del tutto.


6
trè stata una grande idea e la tua copertura complessiva è una risposta di alta qualità.
Nuova Alessandria,

1
+1 per l'utilizzo ( utility standard ) paste... e tutti gli altri!
Totor


4
La parte migliore di questa risposta è che la "risposta lunga" spiega esattamente come e perché il comando funziona.
pdwalker,

3
Questa potrebbe essere la più utile delle migliaia di risposte che ho letto su stackexchange. Devo abbinare più caratteri attraverso le righe. Nessun esempio di sed precedente riguardava più righe e tr non è in grado di gestire la corrispondenza di più caratteri. Perl sembra buono, ma non funziona come mi aspetto. Vorrei votare questa risposta più volte se potessi.
poderoso

225

Un'alternativa awk più breve:

awk 1 ORS=' '

Spiegazione

Un programma awk è costituito da regole costituite da blocchi di codice condizionali, ovvero:

condition { code-block }

Se il codice di blocco viene omesso, il default è utilizzato: { print $0 }. Pertanto, il 1viene interpretato come una vera condizione e print $0viene eseguito per ogni riga.

Quando awklegge l'input, lo divide in record in base al valore di RS(Separatore record), che per impostazione predefinita è una nuova riga, quindi awkper impostazione predefinita analizzerà l'input in linea. La suddivisione comporta anche la rimozione RSdal record di input.

Ora, quando si stampa un record, ORS(Output Record Separator) viene aggiunto ad esso, l'impostazione predefinita è di nuovo una nuova riga. Quindi cambiando ORSin uno spazio tutte le nuove linee vengono cambiate in spazi.


5
Mi piace molto questa semplice soluzione, che è molto più leggibile, rispetto ad altri
Fedir RYKHTIK

8
Se ha più senso, questo potrebbe effettivamente essere scritto come: awk 'BEGIN { ORS=" " } { print $0 } END { print "\n"} ' file.txt(aggiungendo una fine nuova solo per illustrare inizio / fine); "1" valuta true(elabora la riga) e print(stampa la riga). Un condizionale potrebbe anche essere aggiunto a questa espressione, ad esempio, lavorando solo su linee che corrispondono a uno schema: awk 'BEGIN { ORS=" " } /pattern/ { print $0 } END { print "\n"} '
michael,

2
Puoi farlo più semplicemente: codeawk 'ORS = ""' file.txtcode
Udi

Quando si utilizza awk in questo modo, purtroppo anche l'ultimo feed di riga nel file viene eliminato. Vedi la risposta di Patrick Dark sopra sull'uso di 'tr' in una subshell come `cat file | echo $ (tr "\ 012" "") `che fa il trucco. Nifty.
Bernie Reiter il

143

gnu sed ha un'opzione -zper record (righe) nulli. Puoi semplicemente chiamare:

sed -z 's/\n/ /g'

4
Anche se l'input contiene valori null, verranno conservati (come delimitatori di record).
Toby Speight,

6
Questo non caricherà l'intero input se non ci sono valori null? In questo caso l'elaborazione di un file multi-gigabyte potrebbe essere bloccata.
Ruslan

3
@Ruslan, sì, carica l'intero input. Questa soluzione non è una buona idea per i file multi-gigabyte.
JJoao

7
Questa è davvero la migliore risposta. Le altre espressioni sono troppo contorte per ricordare. @JJoao Puoi usarlo con -u, --unbuffered. Il manmago afferma: "carica quantità minime di dati dai file di input e svuota i buffer di output più spesso".
not2qubit,

così. tanto. Questo.
sjas,

85

La versione Perl funziona come previsto.

perl -i -p -e 's/\n//' file

Come sottolineato nei commenti, vale la pena notare che questo modifica in atto. -i.bakti darà un backup del file originale prima della sostituzione nel caso in cui la tua espressione regolare non sia così intelligente come pensavi.


23
Si prega di menzionare almeno che -isenza un suffisso non viene eseguito alcun backup . -i.bakti protegge da un errore facile, brutto (diciamo, dimenticando di digitare -pe azzerando il file).
Telemaco,

6
@Telemaco: è un punto giusto, ma può essere discusso in entrambi i modi. Il motivo principale per cui non l'ho menzionato è che l'esempio sed nella domanda dell'OP non crea backup, quindi qui sembra superfluo. L'altro motivo è che in realtà non ho mai usato la funzionalità di backup (in realtà trovo fastidiosi i backup automatici), quindi dimentico sempre che è lì. Il terzo motivo è che rende la mia riga di comando più lunga di quattro caratteri. Nel bene o nel male (probabilmente peggio), sono un minimalista compulsivo; Preferisco solo la brevità. Mi rendo conto che non sei d'accordo. Farò del mio meglio per ricordare di avvertire in futuro dei backup.
ire_and_curses il

6
@Ire_and_curses: In realtà, hai appena fatto una discussione dannatamente buona per ignorarmi. Cioè, hai ragioni per le tue scelte e, anche se sono d'accordo con le scelte, lo rispetto sicuramente. Non sono del tutto sicuro del perché, ma ultimamente ho avuto una lacrima per questa cosa particolare (la -ibandiera in Perl senza un suffisso). Sono sicuro che troverò qualcos'altro di cui ossessionare abbastanza presto. :)
Telemaco,

È davvero un peccato che questo non funzioni con stdin specificando il -nome del file. C'è un modo per farlo? Questo è il mio modo per non preoccuparti di modificare un file usando una pipeline che inizia con cat.
Steven Lu,

@StevenLu Perl leggerà da STDIN per impostazione predefinita se non vengono forniti nomi di file. Quindi potresti fare ad esempioperl -i -p -e 's/\n//' < infile > outfile
ire_and_curses il

44

Di chi ha bisogno sed? Ecco il bashmodo:

cat test.txt |  while read line; do echo -n "$line "; done

2
In generale, ho usato normalmente la risposta migliore, ma quando eseguo il piping / dev / urandom attraverso di essa, sed non stampa fino a EOF e ^ C non è EOF. Questa soluzione viene stampata ogni volta che vede una nuova riga. Esattamente quello di cui avevo bisogno! Grazie!
Vasiliy Sharapov,

1
allora perché no: echo -n `cat days.txt` Da questo post
Tony,

9
@Tony perché i backtick sono obsoleti e il gatto è ridondante ;-) Usa: echo $ (<days.txt)
seumasmac

10
Senza neanche usare cat: while read line; do echo -n "$line "; done < test.txt. Potrebbe essere utile se una sotto-shell è un problema.
Carlo Cannas,

5
echo $(<file)comprime tutto lo spazio bianco in un unico spazio, non solo nelle nuove linee: questo va oltre ciò che l'OP sta chiedendo.
Glenn Jackman,

27

Per sostituire tutte le newline con spazi usando awk, senza leggere l'intero file in memoria:

awk '{printf "%s ", $0}' inputfile

Se vuoi una nuova riga finale:

awk '{printf "%s ", $0} END {printf "\n"}' inputfile

Puoi usare un personaggio diverso dallo spazio:

awk '{printf "%s|", $0} END {printf "\n"}' inputfile

END{ print ""}è un'alternativa più breve per una nuova riga finale.
Isacco,

22
tr '\n' ' ' 

è il comando.

Semplice e facile da usare.


14
o semplicemente tr -d '\n'se non vuoi aggiungere uno spazio
spuder

21

Tre cose.

  1. tr(o cat, ecc.) non è assolutamente necessario. (GNU)sed e (GNU) awk, se combinati, possono eseguire il 99,9% di qualsiasi elaborazione di testo di cui hai bisogno.

  2. stream! = basato sulla linea. edè un editor basato su linee. sednon è. Vedi lezione di sed per maggiori informazioni sulla differenza. La maggior parte delle persone confonde seddi essere basata sulla linea perché, per impostazione predefinita, non è molto avida nella corrispondenza dei modelli per le partite SEMPLICI - ad esempio, quando si esegue la ricerca dei modelli e la sostituzione di uno o due caratteri, per impostazione predefinita sostituisce solo la prima corrispondenza trova (se non diversamente specificato dal comando globale). Non ci sarebbe nemmeno un comando globale se fosse basato su linea anziché su STREAM, perché valuterebbe solo le linee alla volta. Prova a correre ed; noterai la differenza.edè piuttosto utile se vuoi iterare su linee specifiche (come in un for-loop), ma il più delle volte lo vorrai sed.

  3. Detto ciò,

    sed -e '{:q;N;s/\n/ /g;t q}' file
    

    funziona perfettamente con GNU sedversione 4.2.1. Il comando sopra sostituirà tutte le nuove righe con spazi. È brutto e un po 'ingombrante da digitare, ma funziona bene. È {}possibile tralasciarli, poiché sono inclusi solo per motivi di sanità mentale.


3
Come persona che sa solo abbastanza sedper fare cose di base, devo dire che è più che su ciò che puoi fare, sedma piuttosto quanto sia facile capire cosa sta succedendo. Ho difficoltà a lavorare, sedquindi preferirei un comando più semplice quando posso usarlo.
Nate

Usando t qcome salto condizionale questo funziona con un modello come s/\n / /(per unire tutte le linee che iniziano con uno spazio) senza leggere l'intero file in memoria. Comodo quando si trasformano file da più megabyte.
texthell il

L'articolo che hai collegato non riflette ciò che stai dicendo
hek2mgl,

Questo è quasi 800 volte più lento della risposta accettata su input di grandi dimensioni. Ciò è dovuto alla sostituzione di ogni riga su input sempre più grandi.
Thor,

13

La risposta con: un'etichetta ...

Come posso sostituire una newline (\ n) usando sed?

... non funziona in freebsd 7.2 dalla riga di comando:

(echo foo; echo bar) | sed ': a; N; $! ba; s / \ n / / g'
sed: 1: ": a; N; $! ba; s / \ n / / g": etichetta non utilizzata 'a; N; $! ba; s / \ n / / g'
foo
bar

Ma se metti lo script sed in un file o usi -e per "costruire" lo script sed ...

> (echo foo; echo bar) | sed -e: a -e N -e '$! ba' -e 's / \ n / / g'
foo bar

o ...

> cat > x.sed << eof
:a
N
$!ba
s/\n/ /g
eof

> (echo foo; echo bar) | sed -f x.sed
foo bar

Forse il sed in OS X è simile.


La serie di argomenti -e ha funzionato per me su Windows usando MKS! Grazie!
JamesG

12

Soluzione di facile comprensione

Ho avuto questo problema Il kicker era che avevo bisogno della soluzione per funzionare su BSD (Mac OS X) e GNU (Linux e Cygwin ) sede tr:

$ echo 'foo
bar
baz


foo2
bar2
baz2' \
| tr '\n' '\000' \
| sed 's:\x00\x00.*:\n:g' \
| tr '\000' '\n'

Produzione:

foo
bar
baz

(ha una nuova riga finale)

Funziona su Linux, OS X e BSD - anche senza supporto UTF-8 o con un terminale scadente.

  1. Utilizzare trper scambiare la nuova riga con un altro personaggio.

    NULL( \000o \x00) è utile perché non ha bisogno del supporto UTF-8 e non è probabile che venga utilizzato.

  2. Utilizzare sedper abbinare ilNULL

  3. Utilizzare trper scambiare nuove righe extra se ne hai bisogno


1
Una nota sottile sulla nomenclatura: il carattere \000è comunemente indicato come NUL(una L) e NULLviene generalmente utilizzato quando si parla di un puntatore zero (in C / C ++).
sqweek,


9

Non sono un esperto, ma credo sedche dovresti prima aggiungere la riga successiva nello spazio del pattern, usando " N". Dalla sezione "Multiline Pattern Space" in "Advanced sed Commands" del libro sed & awk (Dale Dougherty e Arnold Robbins; O'Reilly 1997; pagina 107 nell'anteprima ):

Il comando Successivo (N) su più righe crea uno spazio di pattern su più righe leggendo una nuova riga di input e aggiungendolo al contenuto dello spazio di pattern. Il contenuto originale dello spazio pattern e la nuova riga di input sono separati da una nuova riga. Il carattere di nuova riga incorporato può essere adattato in serie dalla sequenza di escape "\ n". In uno spazio di pattern multilinea, il metacarattere "^" corrisponde al primissimo carattere dello spazio di pattern e non al carattere (i) che segue una qualsiasi nuova linea (e) incorporata. Allo stesso modo, "$" corrisponde solo alla nuova riga finale nello spazio del modello e non a qualsiasi nuova riga incorporata. Dopo l'esecuzione del comando Successivo, il controllo viene quindi passato ai comandi successivi nello script.

A partire dal man sed :

[2addr] N

Aggiungi la riga successiva di input allo spazio del pattern, usando un carattere di nuova riga incorporato per separare il materiale aggiunto dal contenuto originale. Si noti che il numero di riga corrente cambia.

Ho usato questo per cercare (più) file di registro mal formattati, in cui la stringa di ricerca può essere trovata su una riga successiva "orfana".


7

Ho usato un approccio ibrido per aggirare la cosa newline usando tr per sostituire le newline con le schede, quindi sostituendo le schede con quello che voglio. In questo caso, "
" poiché sto cercando di generare interruzioni HTML.

echo -e "a\nb\nc\n" |tr '\n' '\t' | sed 's/\t/ <br> /g'`

6

In risposta alla soluzione "tr" sopra, su Windows (probabilmente usando la versione Gnuwin32 di tr), la soluzione proposta:

tr '\n' ' ' < input

non funzionava per me, sarebbe stato un errore o in realtà sostituire \ nw / '' per qualche motivo.

Utilizzando un'altra funzionalità di tr, l'opzione "elimina" -d ha funzionato però:

tr -d '\n' < input

o '\ r \ n' invece di '\ n'


3
Su Windows, probabilmente è necessario utilizzare tr "\n" " " < input. La shell di Windows (cmd.exe) non considera l'apostrofo come un carattere tra virgolette.
Keith Thompson,

No, nel sottosistema Ubuntu di Windows 10, è necessario utilizzaretr "\n\r" " " < input.txt > output.txt
user1491819

Questo funziona su Windows 10 utilizzando GnuWin32: cat SourceFile.txt | tr --delete '\r\n' > OutputFile.txt. Oppure, invece di Gnuwin32, usa Gow (Gnu su Windows), github.com/bmatzelle/gow/wiki
Alchemistmatt

5

Soluzione antiproiettile. Sicuro per i dati binari e conforme POSIX, ma lento.

POSIX sed richiede l'immissione in base al file di testo POSIX e alle definizioni di riga POSIX , pertanto non sono consentiti byte NULL e righe troppo lunghe e ogni riga deve terminare con una nuova riga (inclusa l'ultima riga). Questo rende difficile usare sed per l'elaborazione di dati di input arbitrari.

La seguente soluzione evita sed e converte invece i byte di input in codici ottali e quindi nuovamente in byte, ma intercetta il codice ottale 012 (newline) e genera la stringa di sostituzione al posto di essa. Per quanto ne so, la soluzione è conforme POSIX, quindi dovrebbe funzionare su un'ampia varietà di piattaforme.

od -A n -t o1 -v | tr ' \t' '\n\n' | grep . |
  while read x; do [ "0$x" -eq 012 ] && printf '<br>\n' || printf "\\$x"; done

Documentazione di riferimento POSIX: sh , linguaggio dei comandi della shell , od , tr , grep , read , [ , printf .

Entrambi read, [e printfsono integrati almeno in bash, ma questo probabilmente non è garantito da POSIX, quindi su alcune piattaforme potrebbe essere che ogni byte di input avvii uno o più nuovi processi, che rallenteranno le cose. Anche in bash questa soluzione raggiunge solo circa 50 kB / s, quindi non è adatta per file di grandi dimensioni.

Testato su Ubuntu (bash, dash e busybox), FreeBSD e OpenBSD.


5

In alcune situazioni, forse puoi passare RSa qualche altra stringa o carattere. In questo modo, \ n è disponibile per sub / gsub:

$ gawk 'BEGIN {RS="dn" } {gsub("\n"," ") ;print $0 }' file

Il potere dello scripting della shell è che se non sai come farlo in un modo puoi farlo in un altro modo. E molte volte hai più cose da prendere in considerazione che fare una soluzione complessa su un semplice problema.

Per quanto riguarda la cosa che gawk è lento ... e legge il file in memoria, non lo so, ma a me gawk sembra funzionare con una riga alla volta ed è molto veloce (non così veloce come alcuni degli altri , ma conta anche il tempo di scrivere e provare).

Elaboro MB e persino GB di dati e l'unico limite che ho trovato è la dimensione della linea.


5

Se sei abbastanza sfortunato da dover affrontare le terminazioni di linea di Windows devi rimuovere il \re il\n

tr '[\r\n]' ' ' < $input > $output

Questo sostituisce [con uno spazio, \rcon uno spazio, \ncon uno spazio e ]con uno spazio. tr -d '\r\n' <filerimuoverebbe qualsiasi carattere \ro \n, ma non è anche quello che viene chiesto. tr -d '\r' <filerimuoverà tutti i \rcaratteri (indipendentemente dal fatto che siano adiacenti \n) che è probabilmente più vicino all'essere utile e anche molto probabilmente corretto per le necessità del PO (sempre supponendo che tu trcapisca questa notazione di barra rovesciata).
Tripleee,

4

È possibile utilizzare xargs: verrà sostituito \ncon uno spazio per impostazione predefinita.

Tuttavia, avrebbe problemi se l'input avesse qualche caso di un unterminated quote, ad esempio se i segni di virgolette su una data riga non corrispondono.


xargs gestisce bene anche l'ultima riga:
AAAfarmclub

4

Trova e sostituisce utilizzando il comando \ n

sed -ie -z 's/Marker\n/# Marker Comment\nMarker\n/g' myfile.txt

marcatore

diventa

# Marker Comment

marcatore


4

Perché non ho trovato una soluzione semplice con awk?

awk '{printf $0}' file

printf stamperà ogni riga senza nuove righe, se si desidera separare le righe originali con uno spazio o altro:

awk '{printf $0 " "}' file

echo "1\n2\n3" | awk '{printf $0}', questo funziona per me. @ edi9999
Itachi il

Hai ragione scusa, ho dimenticato di fin printf
edi9999 il

questo è stato l'unico approccio che ha funzionato per me all'interno di git bash per windows
Platone

3

Su Mac OS X (usando FreeBSD sed):

# replace each newline with a space
printf "a\nb\nc\nd\ne\nf" | sed -E -e :a -e '$!N; s/\n/ /g; ta'
printf "a\nb\nc\nd\ne\nf" | sed -E -e :a -e '$!N; s/\n/ /g' -e ta

3

Per rimuovere le righe vuote:

sed -n "s/^$//;t;p;"

Questo è per GNU Sed. In Sed normale, questo dà sed: 1: "s/^$//;t;p;": undefined label ';p;'.
Léo Léopold Hertz

3

Usando Awk:

awk "BEGIN { o=\"\" }  { o=o \" \" \$0 }  END { print o; }"

2
Non è necessario sfuggire alle virgolette e al simbolo del dollaro se si cambiano quelle esterne in virgolette singole. La lettera "o" è generalmente considerata una scelta errata come nome di variabile poiché può essere confusa con la cifra "0". Inoltre, non è necessario inizializzare la variabile, per impostazione predefinita è una stringa nulla. Tuttavia, se non si vuole uno spazio che conduce estranea: awk '{s = s sp $0; sp = " "} END {print s}'. Tuttavia, vedi la mia risposta per un modo di usare awk senza leggere l'intero file in memoria.
In pausa fino a nuovo avviso.

Si prega di verificare la risposta di Thor , invece. E 'il modo più efficiente, leggibile e appena meglio con tutti i mezzi a confronto questo approccio (anche se questo potrebbe funzionare)!
mschilli,

Amico, ho capito. Non c'è bisogno di strofinarlo in faccia :-) La risposta di Thor è comunque molto sopra nella pagina (che è giusto), quindi cosa ti importa?
kralyk,

3

Una soluzione che mi piace particolarmente è quella di aggiungere tutto il file nello spazio di attesa e sostituire tutte le nuove righe alla fine del file:

$ (echo foo; echo bar) | sed -n 'H;${x;s/\n//g;p;}'
foobar

Tuttavia, qualcuno mi ha detto che lo spazio di stiva può essere limitato in alcune implementazioni di sed.


1
la sostituzione con una stringa vuota nella tua risposta nasconde il fatto che l'utilizzo sempre di H per aggiungere allo spazio di attesa significa che lo spazio di attesa inizierà con una nuova riga. Per evitare ciò, è necessario utilizzare1h;2,$H;${x;s/\n/x/g;p}
Jeff

3

Sostituisci newline con qualsiasi stringa e sostituisci anche l'ultima newline

Le trsoluzioni pure possono sostituire solo con un singolo carattere e le sedsoluzioni pure non sostituiscono l'ultima nuova riga dell'input. La seguente soluzione risolve questi problemi e sembra essere sicura per i dati binari (anche con una localizzazione UTF-8):

printf '1\n2\n3\n' |
  sed 's/%/%p/g;s/@/%a/g' | tr '\n' @ | sed 's/@/<br>/g;s/%a/@/g;s/%p/%/g'

Risultato:

1<br>2<br>3<br>

Questo è negativo perché produrrà output indesiderati su qualsiasi input contenente@
Steven Lu

@StevenLu: No, @nell'input è OK. Viene sfuggito %ae ritorno di nuovo. Tuttavia, la soluzione potrebbe non essere completamente conforme a POSIX (byte NULL non consentiti, quindi non va bene per i dati binari e tutte le righe devono terminare con newline, quindi l' troutput non è realmente valido).
Håkon A. Hjortland,

Ah. Vedo che l'hai risolto. Un po 'contorto per quella che dovrebbe essere un'operazione semplice, ma un buon lavoro.
Steven Lu,

3

È sed che introduce le nuove linee dopo la sostituzione "normale". Innanzitutto, taglia il carattere di nuova riga, quindi elabora secondo le tue istruzioni, quindi introduce una nuova riga.

Usando sed puoi sostituire "la fine" di una riga (non il carattere di nuova riga) dopo essere stata ritagliata, con una stringa di tua scelta, per ogni riga di input; ma, sed produrrà linee diverse. Ad esempio, supponiamo di voler sostituire la "fine riga" con "===" (più generale di una sostituzione con un singolo spazio):

PROMPT~$ cat <<EOF |sed 's/$/===/g'
first line
second line
3rd line
EOF

first line===
second line===
3rd line===
PROMPT~$

Per sostituire il carattere di nuova riga con la stringa, è possibile, in modo inefficiente, utilizzare tr , come indicato in precedenza, per sostituire i caratteri di nuova riga con un "carattere speciale" e quindi utilizzare sed per sostituire quel carattere speciale con la stringa desiderata .

Per esempio:

PROMPT~$ cat <<EOF | tr '\n' $'\x01'|sed -e 's/\x01/===/g'
first line
second line
3rd line
EOF

first line===second line===3rd line===PROMPT~$

3

Puoi usare questo metodo anche

sed 'x;G;1!h;s/\n/ /g;$!d'

Spiegazione

x   - which is used to exchange the data from both space (pattern and hold).
G   - which is used to append the data from hold space to pattern space.
h   - which is used to copy the pattern space to hold space.
1!h - During first line won't copy pattern space to hold space due to \n is
      available in pattern space.
$!d - Clear the pattern space every time before getting next line until the
      last line.

Flusso:
quando la prima riga ottiene dall'input, viene effettuato lo scambio, quindi 1 va a trattenere lo spazio e \ n arriva allo spazio del pattern, quindi aggiungendo lo spazio di mantenimento allo spazio del pattern, quindi viene eseguita la sostituzione ed eliminato lo spazio del pattern.
Durante lo scambio della seconda riga, 2 va a trattenere lo spazio e 1 arriva allo spazio del motivo, quindi Gaggiungere lo spazio di mantenimento nello spazio del motivo, quindi hcopiare il motivo su di esso e la sostituzione viene effettuata ed eliminata. Questa operazione continua fino al raggiungimento di Eof, quindi stampa il risultato esatto.


Tuttavia, tieni presente che ciò echo 'Y' | sed 'x;G;1!h;s/\n/X/g;$!d'comporta XY.
Spettrale

3

Altro GNU sed metodo, quasi lo stesso di Zsolt Botykai 's risposta , ma utilizza sed' s utilizzato meno frequentemente y( traslitterare comando), che consente di risparmiare un byte di codice (il finale g):

sed ':a;N;$!ba;y/\n/ /'

Si potrebbe sperare di ycorrere più veloce di s(forse a trvelocità, 20 volte più veloce), ma in GNU sed v4.2.2 y è circa il 4% più lento di s.


Versione BSD più portatile sed:

sed -e ':a' -e 'N;$!ba' -e 'y/\n/ /'

2
Con BSD sed yè circa il 15% più veloce. Vedi questa risposta per un esempio funzionante.
Thor,

Inoltre, con BSD i comandi sed devono terminare dopo un'etichetta, quindi sed -e ':a' -e 'N;$!ba' -e 'y/\n/ /'sarebbe la strada da percorrere.
ghoti,
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.