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:
- Maak een label via
:a
. - Voeg de huidige en volgende regel toe aan de patroonruimte via
N
. - 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). - 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 sed
van 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 sed
voor dit verder eenvoudige probleem problematisch. Voor een eenvoudigere en adequatere oplossing zie dit antwoord.
Antwoord 2, autoriteit 94%
sed
is bedoeld voor gebruik op lijngebaseerde invoer. Hoewel het kan doen wat je nodig hebt.
Een betere optie hier is om de opdracht tr
als 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
- :amaak een label ‘a’
- Nvoeg de volgende regel toe aan de patroonruimte
- $!indien niet de laatste regel, batak (ga naar) label ‘a’
- 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 1
geïnterpreteerd als een echte conditie en print $0
wordt voor elke regel uitgevoerd.
Wanneer awk
leest de invoer die het in records splitst op basis van de waarde van RS
(Record Separator), die standaard een nieuwlijn is, dus awk
MARSE PARSES DE INPUT LINE-WISE. De splitsing omvat ook het uitschakelen van RS
van 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 ORS
naar 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 sed
nodig? Hier is de bash
WEG:
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.
-
tr
(ofcat
, etc.) is absoluut niet nodig. (GNU)sed
en (GNU)awk
kunnen, indien gecombineerd, 99,9% van alle tekstverwerking uitvoeren die u nodig heeft. -
stream != gebaseerd op regels.
ed
is een op regels gebaseerde editor.sed
is dat niet. Zie sed-lezingvoor meer informatie over het verschil. De meeste mensen verwarrensed
met 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. Probeered
uit te voeren; je zult het verschil merken.ed
is best handig als je specifieke regels wilt herhalen (zoals in een for-loop), maar meestal wil je gewoonsed
. -
Dat gezegd hebbende,
sed -e '{:q;N;s/\n/ /g;t q}' file
werkt prima in GNU
sed
versie 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 ) sed
en 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.
-
Gebruik
tr
om de nieuwe regel te wisselen met een ander teken.NULL
(\000
of\x00
) is leuk omdat het geen UTF-8-ondersteuning nodig heeft en dat waarschijnlijk ook niet zal zijn gebruikt. -
Gebruik
sed
om deNULL
-
Gebruik
tr
om extra nieuwe regels terug te ruilen als je ze nodig hebt
aan te passen
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
printf
print 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 \r
en de \n
:
verwijderen
tr '\r\n' ' ' < $input > $output
15
Ik ben geen expert, maar ik denk dat in sed
je 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 RS
wijzigen 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 1
gaat naar de spatie en \n
komt 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, 2
gaat naar de spatie en 1
komt naar de patroonruimte, g
voegt de houd spatie in de patroonruimte, h
kopieer 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 xargs
kunnen gebruiken — het zal standaard \n
vervangen door een spatie.
Het zou echter problemen opleveren als uw invoer een unterminated quote
bevat, 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 y
sneller zou werken dan s
, (misschien op tr
snelheden, 20x sneller), maar in GNU sed v4.2.2y
is ongeveer 4%langzamer dan s
.
Meer draagbare BSDsed
versie:
sed -e ':a' -e 'N;$!ba' -e 'y/\n/ /'