Hoe kan ik een nieuwe regel (\n) vervangen met sed?

Hoe kan ik een nieuwe regel (“\n“) vervangen door een spatie (““) met de opdracht sed?

Ik heb tevergeefs geprobeerd:

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

Hoe los ik het op?


Antwoord 1, autoriteit 100%

Gebruik deze oplossing met GNU sed:

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

Dit leest het hele bestand in een lus en vervangt vervolgens de nieuwe regel(s) door een spatie.

Uitleg:

  1. Maak een label via :a.
  2. Voeg de huidige en volgende regel toe aan de patroonruimte via N.
  3. Als we voor de laatste regel staan, vertakt u naar het gemaakte label $!ba($!betekent dat u het niet op de laatste regel moet doen, omdat er een zou moeten zijn laatste nieuwe regel).
  4. Ten slotte vervangt de vervanging elke nieuwe regel door een spatie op de patroonruimte (wat het hele bestand is).

Hier is een platformonafhankelijke syntaxis die werkt met sedvan BSD en OS X (volgens @Benjie opmerking):

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

Zoals je kunt zien, is het gebruik van sedvoor dit verder eenvoudige probleem problematisch. Voor een eenvoudigere en adequatere oplossing zie dit antwoord.


Antwoord 2, autoriteit 94%

sedis bedoeld voor gebruik op lijngebaseerde invoer. Hoewel het kan doen wat je nodig hebt.


Een betere optie hier is om de opdracht trals volgt te gebruiken:

tr '\n' ' ' < input_filename

of verwijder de tekens van de nieuwe regel volledig:

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

of als je de GNU-versie hebt (met zijn lange opties)

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

Antwoord 3, autoriteit 34%

Snel antwoord

sed ':a;N;$!ba;s/\n/ /g' file
  1. :amaak een label ‘a’
  2. Nvoeg de volgende regel toe aan de patroonruimte
  3. $!indien niet de laatste regel, batak (ga naar) label ‘a’
  4. svervanging, /\n/regex voor nieuwe regel, / /door een spatie, /galgemene overeenkomst (zo vaak als mogelijk)

sed doorloopt stap 1 tot 3 totdat het de laatste regel bereikt, waarbij alle regels in de patroonruimte passen waar sed alle \n tekens

vervangt


Alternatieven

Alle alternatieven hoeven, in tegenstelling tot sed, niet de laatste regel te bereiken om het proces te starten

met bash, langzaam

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

met perl, sed-achtige snelheid

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

met tr, sneller dan sed, kan slechts door één teken worden vervangen

tr '\n' ' ' < file

met plakken, tr-achtige snelheid, kan slechts door één teken worden vervangen

paste -s -d ' ' file

met awk, tr-achtige snelheid

awk 1 ORS=' ' file

Ander alternatief zoals “echo $(< file)”is traag, werkt alleen op kleine bestanden en moet het hele bestand verwerken om het proces te starten.


Lang antwoord van de sed FAQ 5.10

5.10. Waarom kan ik een nieuwe regel niet matchen of verwijderen met de \n escape
volgorde? Waarom kan ik 2 of meer regels niet matchen met \n?

De \n komt nooit overeen met de nieuwe regel aan het einde van de regel omdat de
nieuwe regel wordt altijd verwijderd voordat de regel in de
. wordt geplaatst
patroon ruimte. Gebruik
. om 2 of meer lijnen in de patroonruimte te krijgen
het ‘N’-commando of iets dergelijks (zoals ‘H;…;g;’).

Sed werkt als volgt: sed leest regel voor regel, hakt de
beëindigen van nieuwe regel, plaatst wat over is in de patroonruimte waar
het sed-script kan het adresseren of wijzigen, en wanneer de patroonruimte
wordt afgedrukt, voegt een nieuwe regel toe aan stdout (of aan een bestand). Als de
patroonruimte wordt geheel of gedeeltelijk verwijderd met ‘d’ of ‘D’, de
newline wordt in dergelijke gevallen niettoegevoegd. Dus scripts zoals

 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         

werkt NOOIT, omdat de laatste nieuwe regel vóór
wordt verwijderd
de lijn wordt in de patroonruimte geplaatst. Om de bovenstaande taken uit te voeren,
gebruik in plaats daarvan een van deze scripts:

 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          

Omdat versies van SED anders dan GNU SED beperkingen hebben tot de grootte van
De patroonbuffer, het UNIX ‘TR’-hulpprogramma heeft hier de voorkeur.
Als de laatste regel van het bestand een newline bevat, zal GNU SED toevoegen |
die newline aan de uitvoer maar verwijder alle anderen, terwijl TR ZAL
Verwijder alle newlines.

Om een ​​blok van twee of meer regels te matchen, zijn er 3 basiskeuzes:
(1) Gebruik de opdracht ‘N’ om de volgende regel aan de patroonruimte toe te voegen;
(2) Gebruik de opdracht ‘H’ minstens twee keer om de huidige lijn te voegen
naar de houd ruimte en haal dan de lijnen op van de ruimtevloeistof
met x, g of g; of (3) adresbereiken (zie paragraaf 3.3, hierboven)
om lijnen tussen twee opgegeven adressen aan te passen.

Keuzes (1) en (2) zullen een \ N in de patroonruimte zetten, waar het was
kan als gewenst worden aangepakt (‘s / abc \ nxyz / alfabet / g’). Een voorbeeld
van het gebruik van ‘n’ om een ​​bloklijnen te verwijderen verschijnt in sectie 4.13
(“Hoe verwijder ik een blok specifiek opeenvolgende regels?”). Deze
Voorbeeld kan worden gewijzigd door de opdracht Verwijderen naar Iets te wijzigen
anders, zoals ‘p’ (print), ‘I’ (Insert), ‘C’ (verandering), ‘A’ (APPEND),
of ‘s’ (vervanging).

Keuze (3) zal geen \ N in de patroonruimte plaatsen, maar het doet
Match een blok van opeenvolgende lijnen, dus het kan zijn dat je niet doet
heb zelfs de \ n nodig om te vinden waarnaar u op zoek bent. Sinds GNU SED
versie 3.02.80 ondersteunt nu deze syntaxis:

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

Naast de traditionele ‘/ van hier /, / naar daar / {…}’ bereik
adressen, het kan mogelijk zijn om het gebruik van \ N volledig te vermijden.


4, Autoriteit 14%

Een korter AWK-alternatief:

awk 1 ORS=' '

Uitleg

Een AWK-programma is opgebouwd uit regels die bestaan ​​uit voorwaardelijke code-blokken, d.w.z.:

condition { code-block }

Als het codeblok is weggelaten, wordt de standaard gebruikt: { print $0 }. Aldus wordt de 1geïnterpreteerd als een echte conditie en print $0wordt voor elke regel uitgevoerd.

Wanneer awkleest de invoer die het in records splitst op basis van de waarde van RS(Record Separator), die standaard een nieuwlijn is, dus awkMARSE PARSES DE INPUT LINE-WISE. De splitsing omvat ook het uitschakelen van RSvan het invoerrecord.

Nu, bij het afdrukken van een record, wordt ORS(uitgangsrecord-scheidingsscheider) bijgevoegd, is de standaardinstelling opnieuw een nieuwe lijn. Dus door het wijzigen van ORSnaar een spatie, worden alle newlines gewijzigd in spaties.


5, Autoriteit 11%

GNU SED heeft een optie, -z, voor niet-gescheiden records (regels). U kunt gewoon bellen:

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

6, Autoriteit 3%

Wie heeft sednodig? Hier is de bashWEG:

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

Antwoord 7, autoriteit 2%

Om alle nieuwe regels te vervangen door spaties met awk, zonder het hele bestand in het geheugen te lezen:

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

Als je een laatste nieuwe regel wilt:

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

U kunt een ander teken dan spatie gebruiken:

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

Antwoord 8

tr '\n' ' ' 

is het commando.

Eenvoudig en gemakkelijk te gebruiken.


Antwoord 9

Drie dingen.

  1. tr(of cat, etc.) is absoluut niet nodig. (GNU) seden (GNU) awkkunnen, indien gecombineerd, 99,9% van alle tekstverwerking uitvoeren die u nodig heeft.

  2. stream != gebaseerd op regels. edis een op regels gebaseerde editor. sedis dat niet. Zie sed-lezingvoor meer informatie over het verschil. De meeste mensen verwarren sedmet lijngebaseerd omdat het standaard niet erg gulzig is in het matchen van patronen voor EENVOUDIGE overeenkomsten – bijvoorbeeld bij het zoeken naar patronen en het vervangen door een of twee tekens, wordt standaard alleen vervangen bij de eerste overeenkomst die wordt gevonden (tenzij anders aangegeven door de algemene opdracht). Er zou zelfs geen globaal commando zijn als het op regels was gebaseerd in plaats van op STREAM, omdat het alleen regels tegelijk zou evalueren. Probeer eduit te voeren; je zult het verschil merken. edis best handig als je specifieke regels wilt herhalen (zoals in een for-loop), maar meestal wil je gewoon sed.

  3. Dat gezegd hebbende,

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

    werkt prima in GNU sedversie 4.2.1. De bovenstaande opdracht vervangt alle nieuwe regels door spaties. Het is lelijk en een beetje omslachtig om in te typen, maar het werkt prima. De {}‘s kunnen worden weggelaten, omdat ze alleen om gezondheidsredenen zijn opgenomen.


Antwoord 10

Eenvoudig te begrijpen oplossing

Ik had dit probleem. De kicker was dat ik de oplossing nodig had om te werken op BSD’s (Mac OS X) en GNU’s (Linux en Cygwin ) seden tr:

$ echo 'foo
bar
baz
foo2
bar2
baz2' \
| tr '\n' '\000' \
| sed 's:\x00\x00.*:\n:g' \
| tr '\000' '\n'

Uitvoer:

foo
bar
baz

(heeft een nieuwe regel)

Het werkt op Linux, OS X en BSD– zelfs zonder UTF-8-ondersteuning of met een waardeloze terminal.

  1. Gebruik trom de nieuwe regel te wisselen met een ander teken.

    NULL(\000of \x00) is leuk omdat het geen UTF-8-ondersteuning nodig heeft en dat waarschijnlijk ook niet zal zijn gebruikt.

  2. Gebruik sedom de NULL

  3. aan te passen

  4. Gebruik trom extra nieuwe regels terug te ruilen als je ze nodig hebt


Antwoord 11

Het antwoord met het :a label …

Hoe kan ik een nieuwe regel vervangen (\n ) sed gebruiken?

… werkt niet in freebsd 7.2 op de opdrachtregel:

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

Maar als u het SED-script in een bestand plaatst of gebruikt om het SED-script te “bouwen” …

& GT; (echo foo; echo bar) | SED -E: A -E N -E '$! BA' -E 'S / \ N / / G'
foo bar

of …

> cat > x.sed << eof
:a
N
$!ba
s/\n/ /g
eof
> (echo foo; echo bar) | sed -f x.sed
foo bar

Misschien is de SED in OS X vergelijkbaar.


12

U kunt xargs gebruiken:

seq 10 | xargs

of

seq 10 | xargs echo -n

13

Waarom heb ik geen eenvoudige oplossing gevonden met awk?

awk '{printf $0}' file

printfprint de elke regel zonder newlines, als u de oorspronkelijke regels met een ruimte of andere wilt scheiden:

awk '{printf $0 " "}' file

14

Als u jammer genoeg bent om te gaan met Windows Line-eindes, moet u de \ren de \n:

verwijderen

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

15

Ik ben geen expert, maar ik denk dat in sedje eerst de volgende regel in de patroonruimte, bij het gebruik van “N” hoeven toe te voegen. Uit het gedeelte “Multiline Pattern Space” in “Geavanceerde SED-opdrachten” van het boek sed & amp; AWK (Dale Dougherty en Arnold Robbins; O’Reilly 1997; Pagina 107 in De preview ):

De opdracht Volgende (N) met meerdere regels maakt een patroonruimte met meerdere regels door een nieuwe invoerregel te lezen en deze toe te voegen aan de inhoud van de patroonruimte. De oorspronkelijke inhoud van patroonruimte en de nieuwe invoerregel worden gescheiden door een nieuwe regel. Het ingesloten newline-teken kan in patronen worden gematcht door de escape-reeks “\n”. In een patroonruimte met meerdere regels komt het metateken “^” overeen met het allereerste teken van de patroonruimte, en niet met de tekens die volgen op een of meer ingesloten nieuwe regels. Evenzo komt “$” alleen overeen met de laatste nieuwe regel in de patroonruimte, en niet met ingesloten nieuwe regel(s). Nadat de opdracht Volgende is uitgevoerd, wordt de besturing doorgegeven aan de volgende opdrachten in het script.

Van man sed:

[2addr]N

Voeg de volgende invoerregel toe aan de patroonruimte, met een ingesloten teken voor een nieuwe regel om het toegevoegde materiaal te scheiden van de oorspronkelijke inhoud. Merk op dat het huidige regelnummer verandert.

Ik heb gebruikt ditom (meerdere) slecht opgemaakte logbestanden te doorzoeken, waarin de zoekstring kan worden gevonden op een “verweesde” volgende regel.


Antwoord 16

Als reactie op de “tr”-oplossing hierboven, op Windows (waarschijnlijk met behulp van de Gnuwin32-versie van tr), de voorgestelde oplossing:

tr '\n' ' ' < input

werkte niet voor mij, het zou een fout geven of om de een of andere reden de \n w/ ” vervangen.

Door een andere functie van tr te gebruiken, werkte de optie “verwijderen” -d wel:

tr -d '\n' < input

of ‘\r\n’ in plaats van ‘\n’


Antwoord 17

Ik heb een hybride benadering gebruikt om rond het nieuwe lijn te gaan met behulp van TR om nieuwe lijnen te vervangen door tabbladen en vervolgens tabbladen vervangen door wat ik wil. In dit geval, “
” sinds ik probeer om HTML-breaks te genereren.

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

18

In sommige situaties kunt u misschien RSwijzigen op een andere reeks of een teken. Op deze manier is \ N beschikbaar voor sub / gsub:

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

De kracht van Shell Scripting is dat als je niet weet hoe je het op een manier moet doen, je het op een andere manier kunt doen. En vele malen heb je meer dingen om rekening mee te houden dan een complexe oplossing op een eenvoudig probleem.

Wat betreft het ding dat Gawk traag is … en leest het bestand in het geheugen, ik weet dit niet, maar voor mij lijkt Gawk op het moment met één regel te werken en is heel snel (niet zo snel als sommigen van de anderen, maar de tijd om te schrijven en testen telt ook).

Ik verwerk MB en zelfs GB aan gegevens en de enige limiet die ik vond is lijngrootte.


19

vindt en vervangt het toestaan ​​van \ N

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

Markering

Wordt

# Markeringsreactie

Markering


Antwoord 20

U kunt ook deze methode gebruiken:

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

Uitleg

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 the next line until the
      the last line.

Stroom

Als de eerste regel van de invoer komt, wordt er gewisseld, dus 1gaat naar de spatie en \nkomt naar de patroonruimte, waarbij de spatie wordt toegevoegd aan patroonruimte, en een vervanging wordt uitgevoerd en verwijdert de patroonruimte.

Tijdens de tweede regel wordt een uitwisseling gemaakt, 2gaat naar de spatie en 1komt naar de patroonruimte, gvoegt de houd spatie in de patroonruimte, hkopieer het patroon ernaar, de vervanging is gemaakt en verwijderd. Deze bewerking wordt voortgezet totdat EOF is bereikt en het exacte resultaat wordt afgedrukt.


Antwoord 21

Je zou xargskunnen gebruiken — het zal standaard \nvervangen door een spatie.

Het zou echter problemen opleveren als uw invoer een unterminated quotebevat, b.v. als de aanhalingstekens op een bepaalde regel niet overeenkomen.


Antwoord 22

Op Mac OS X (met 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

Antwoord 23

Lege regels verwijderen:

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

Antwoord 24

Awk gebruiken:

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

Antwoord 25

Een oplossing die ik vooral leuk vind, is om al het bestand in de wachtruimte toe te voegen en alle nieuwe regels aan het einde van het bestand te vervangen:

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

Iemand zei me echter dat de wachtruimte in sommige sed-implementaties eindig kan zijn.


Antwoord 26

Vervang nieuwe regels door een willekeurige tekenreeks en vervang ook de laatste nieuwe regel

De pure tr-oplossingen kunnen alleen vervangen worden door een enkel teken, en de pure sed-oplossingen vervangen de laatste nieuwe regel van de invoer niet. De volgende oplossing lost deze problemen op en lijkt veilig te zijn voor binaire gegevens (zelfs met een UTF-8-landinstelling):

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

Resultaat:

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

Antwoord 27

Het is seddat de nieuwe regels introduceert na “normale” vervanging. Eerst trimt het de nieuwe regel char, dan verwerkt het volgens uw instructies, dan introduceert het een nieuwe regel.

Met sedkun je “het einde” van een regel (niet de nieuwe regel char) vervangen door een string naar keuze voor elke invoerregel; maar sedzal verschillende regels uitvoeren. Stel bijvoorbeeld dat u het “einde van de regel” wilt vervangen door “===” (algemeen dan een vervanging met een enkele spatie):

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

Om het nieuwe-regelteken door de tekenreeks te vervangen, kunt u, echter inefficiënt, trgebruiken, zoals eerder aangegeven, om de nieuweregeltekens te vervangen door een “speciaal teken” en vervolgens sedom die speciale char te vervangen door de gewenste string.

Bijvoorbeeld:

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~$

Antwoord 28

Een andere GNUsed-methode, bijna hetzelfde als Zsolt Botykai‘s antwoord, maar dit gebruikt sed‘s minder vaak gebruikte y(transliterate) commando, die één byteaan code opslaat (de achterliggende g):

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

Je zou hopen dat ysneller zou werken dan s, (misschien op trsnelheden, 20x sneller), maar in GNU sed v4.2.2yis ongeveer 4%langzamer dan s.


Meer draagbare BSDsedversie:

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

Other episodes