trjest tylko odpowiednim narzędziem do zadania, jeśli zamienisz pojedynczy znak na pojedynczy znak, podczas gdy powyższy przykład pokazuje zamień znak nowej linii spacją .. Więc w powyższym przykładzie tr może działać .. Ale będzie później ograniczać.
Angry 84
9
trw odpowiednim narzędziu do pracy, ponieważ pytający chciał zastąpić każdą nową linię spacją, jak pokazano w jego przykładzie. Zastąpienie nowych linii jest wyjątkowo tajemnicze, sedale łatwe do wykonania tr. To jest częste pytanie. Wykonanie zamiany wyrażenia regularnego nie jest wykonywane przez, trale przez sed, co byłoby właściwym narzędziem ... na inne pytanie.
Mike S
3
„tr” może również po prostu usunąć nowy wiersz `tr -d '\ n' ', ale możesz również chcieć usunąć znaki powrotu, aby być bardziej uniwersalnym` tr -d' \ 012 \ 015 ''.
Anthony
2
OSTRZEŻENIE: „tr” działa inaczej w zakresie zakresów znaków między Linuksem a starszymi komputerami Solaris (EG sol5.8). EG: `tr -d 'az' 'i` tr -d' [az] ''. Do tego polecam użyć „sed”, który nie ma tej różnicy.
Anthony
2
@MikeS Dzięki za odpowiedź. Postępuj zgodnie tr '\012' ' 'z echo. W przeciwnym razie usuwany jest również ostatni kanał w pliku. tr '\012' ' ' < filename; echoZrób sztuczkę.
Bernie Reiter,
Odpowiedzi:
1513
Użyj tego rozwiązania z GNU sed:
sed ':a;N;$!ba;s/\n/ /g' file
Spowoduje to odczytanie całego pliku w pętli, a następnie zastąpienie nowego wiersza (ów) spacją.
Wyjaśnienie:
Utwórz etykietę za pomocą :a.
Dołącz bieżącą i następną linię do przestrzeni wzorów za pomocą N.
Jeśli znajdujemy się przed ostatnim wierszem, przejdź do utworzonej etykiety $!ba( $!oznacza to, że nie należy tego robić w ostatnim wierszu, ponieważ powinna istnieć jedna końcowa nowa linia).
W końcu podstawienie zastępuje każdą nową linię spacją w przestrzeni wzorców (która jest całym plikiem).
Oto składnia kompatybilna z wieloma platformami, która działa z BSD i OS X sed(zgodnie z komentarzem @Benjie ):
sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/ /g' file
Jak widać, użycie sedtego prostego problemu jest problematyczne. Aby uzyskać prostsze i odpowiednie rozwiązanie, zobacz tę odpowiedź .
@Arjan i Masi: OS X używa BSD sedzamiast GNU sed, więc mogą występować pewne subtelne (i niektóre nie tak subtelne) różnice między nimi. Jest to ciągły ból, jeśli pracujesz zarówno na komputerach z systemem OS X, jak i * nix. Zwykle instaluję GNU coreutilsi findutilsOS OS i ignoruję wersje BSD.
Telemachus
50
To :anie jest rejestr, to etykieta oddziału. Jest to cel bpolecenia *, który działa jak „goto”. Nazwanie go rejestrem oznacza, że możesz tworzyć lokalizacje pamięci. Istnieją tylko dwa „rejestry”; jedna nazywa się „przestrzenią wstrzymania”, której skrypt nie używa, a druga „przestrzenią wzorców”. NPolecenie dołącza do nowej linii i i następny wiersz pliku wejściowego do przestrzeni wzorca. [* Możesz mieć wiele etykiet i bpoleceń. Jeśli masz bpolecenie bez dołączonego do niego znaku etykiety, rozgałęzia się ono na końcu skryptu, aby przeczytać następny wiersz i zapętlić ponownie.]
Wstrzymano do odwołania.
108
Możesz uruchomić tę platformę (np. W systemie Mac OS X), wykonując osobno polecenia zamiast oddzielając je średnikami: sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/ /g'
Benjie
74
Dlaczego nikt nie komentuje, jaki to głupi bałagan (nie sama odpowiedź, ale program, dla którego proponowana odpowiedź jest najlepszym rozwiązaniem bardzo prostego problemu). Sed wygląda jak samochód, który zwykle działa dobrze, ale jeśli chcesz jechać na określoną pobliską ulicę, jedynym sposobem jest podniesienie samochodu za pomocą helikoptera.
Ark-kun
12
Chodźcie ludzie - 261 głosów za szalonym, niezrozumiałym rozwiązaniem, które nie działa ???? sed jest doskonałym narzędziem do prostych zapisów w jednej linii, do wszystkiego innego wystarczy użyć awk. Dobry żal ....
Ed Morton
1711
sedjest przeznaczony do użycia z danymi wejściowymi opartymi na linii. Chociaż może zrobić to, czego potrzebujesz.
Lepszą opcją jest tutaj użycie trpolecenia w następujący sposób:
Sed jest oparty na linii, dlatego trudno jest uchwycić nowe linie.
Alexander Gladysh
191
sed działa na „strumieniu” danych wejściowych, ale rozumie je w kawałkach rozdzielanych znakami nowej linii. Jest to narzędzie uniksowe, co oznacza, że robi jedną rzecz bardzo dobrze. Jedną rzeczą jest „praca nad plikiem liniowo”. Zmuszenie go do zrobienia czegoś innego będzie trudne i grozi błędem. Morał tej historii jest następujący: wybierz odpowiednie narzędzie. Wiele z twoich pytań wydaje się przybrać formę „Jak sprawić, by to narzędzie zrobiło coś, czego nigdy nie zamierzano?” Te pytania są interesujące, ale jeśli pojawią się w trakcie rozwiązywania prawdziwego problemu, prawdopodobnie robisz to źle.
dmckee --- były kot moderator
7
@JBBrown trto często pomijany klejnot do budowy rurociągów.
dmckee --- były moderator kociak
70
tr jest świetny, ale możesz zastąpić znaki nowej linii pojedynczymi znakami. Musisz użyć innego narzędzia, jeśli chcesz zastąpić znaki nowej linii ciągiem
Eddy
21
@Eddy - użyłem tr, aby zastąpić nowe wiersze znakiem, który nie pojawił się w tekście (użyłem backticka), a następnie sed, aby zastąpić backtick ciągiem, którego chciałem użyć
rjohnston 30.01.2013
493
Szybka odpowiedź
sed ':a;N;$!ba;s/\n/ /g' file
: a utwórz etykietę „a”
N. dodaj następny wiersz do obszaru wzorów
$! jeśli nie ostatnia linia , ba gałąź (przejdź do) oznacz „a”
s zamiennik , / \ n / regex dla nowej linii , / / spacją , / g dopasowanie globalne (tyle razy, ile to możliwe)
sed będzie przechodzić od kroku 1 do 3, aż dojdzie do ostatniej linii, dopasowując wszystkie linie do obszaru wzorów, gdzie sed zastąpi wszystkie \ n znaków
Alternatywy
Wszystkie alternatywy, w przeciwieństwie do sed , nie będą musiały dotrzeć do ostatniej linii, aby rozpocząć proces
z uderzeniem , powoli
while read line;do printf "%s""$line ";done< file
z Perl , sed -jak prędkość
perl -p -e 's/\n/ /' file
z tr , szybszy niż sed , można zastąpić tylko jedną postacią
tr '\n'' '< file
z wklejaniem , prędkość podobna do tr , można zastąpić tylko jedną postacią
paste -s -d ' ' file
z awk , tr- podobną prędkością
awk 1 ORS=' ' file
Inne alternatywy, takie jak „echo $ (<plik)”, są powolne, działają tylko na małych plikach i muszą przetworzyć cały plik, aby rozpocząć proces.
5.10 Dlaczego nie mogę dopasować ani usunąć nowego wiersza za pomocą
sekwencji ucieczki \ n ? Dlaczego nie mogę dopasować 2 lub więcej linii za pomocą \ n?
\ N nigdy nie będzie pasować do nowej linii na końcu linii, ponieważ
nowa linia jest zawsze usuwana przed umieszczeniem linii w obszarze
wzorów. Aby wstawić 2 lub więcej linii do przestrzeni wzorów, użyj
polecenia „N” lub czegoś podobnego (takiego jak „H; ...; g;”).
Sed działa w ten sposób: sed odczytuje jedną linię na raz, odcina
kończącą się nową linię , umieszcza to, co pozostało w przestrzeni wzorcowej, w której
skrypt sed może ją adresować lub zmieniać, a gdy
drukowana jest przestrzeń wzorcowa, dodaje nową linię do standardowego wejścia (lub do pliku). Jeśli
przestrzeń wzoru zostanie całkowicie lub częściowo usunięta za pomocą „d” lub „D”,
nowa linia nie jest dodawana w takich przypadkach. Tak więc skrypty lubią
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
NIGDY nie zadziała, ponieważ końcowy znak nowej linii jest usuwany przed
wstawieniem linii do obszaru wzorów. Aby wykonać powyższe zadania,
użyj jednego z tych skryptów:
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
Ponieważ wersje sed inne niż GNU sed mają ograniczenia wielkości
bufora wzorców, należy tutaj preferować narzędzie uniksowe „tr”.
Jeśli ostatni wiersz pliku zawiera nową linię, GNU sed doda
tę nową linię do wyniku, ale usunie wszystkie inne, podczas gdy tr doda
usunie wszystkie nowe linie.
Aby dopasować blok dwóch lub więcej wierszy, istnieją 3 podstawowe opcje:
(1) użyj polecenia „N”, aby dodać następny wiersz do obszaru wzorów;
(2) użyj polecenia „H” co najmniej dwukrotnie, aby dołączyć bieżącą linię
do przestrzeni Hold, a następnie pobrać linie z przestrzeni Hold za
pomocą x, g lub G; lub (3) użyj zakresów adresów (patrz sekcja 3.3 powyżej),
aby dopasować linie między dwoma określonymi adresami.
Wybory (1) i (2)
wstawią \ n do przestrzeni wzorców, gdzie można ją adresować według potrzeb ('s / ABC \ nXYZ / alfabet / g'). Jeden przykład
użycia „N” do usunięcia bloku linii pojawia się w sekcji 4.13
(„Jak usunąć blok określonych kolejnych linii?”). Ten
przykład można zmodyfikować, zmieniając polecenie delete na coś
innego, na przykład „p” (drukuj), „i” (wstaw), „c” (zmiana), „a” (dołącz)
lub „s” (zamiennik) .
Choice (3) nie położy \ n do przestrzeni wzorca, ale nie
pasuje do bloku kolejnych wierszy, więc może się okazać, że nie masz
jeszcze potrzebne \ n, aby znaleźć to, czego szukasz. Ponieważ
wersja GNU sed 3.02.80 obsługuje teraz tę składnię:
sed '/start/,+4d'# to delete "start" plus the next 4 lines,
oprócz tradycyjnych
adresów z zakresu „/ from here /, / to there / {...}” można całkowicie uniknąć użycia \ n.
Najlepsze w tej odpowiedzi jest to, że „długa odpowiedź” dokładnie wyjaśnia, w jaki sposób i dlaczego to polecenie działa.
pdwalker
3
To może być najbardziej pomocna z tysięcy odpowiedzi, które przeczytałem na stackexchange. Muszę dopasować wiele znaków w liniach. Żaden poprzedni przykład sed nie obejmował wielu linii, a tr nie może obsłużyć dopasowania wielu znaków. Perl wygląda dobrze, ale nie działa tak, jak się spodziewam. Głosowałbym na tę odpowiedź kilka razy, gdybym mógł.
mightypile
225
Krótsza alternatywa awk:
awk 1 ORS=' '
Wyjaśnienie
Program awk składa się z reguł składających się z bloków kodu warunkowego, tj .:
condition { code-block }
Jeśli kod blok zostanie pominięty, domyślnie jest używany: { print $0 }. Zatem 1interpretowany jest jako prawdziwy warunek i print $0jest wykonywany dla każdej linii.
Podczas awkodczytywania danych wejściowych dzieli je na rekordy na podstawie wartości RS(Separator rekordów), który domyślnie jest nowym awkwierszem , a zatem domyślnie parsuje dane wejściowe liniowo. Podział obejmuje również usunięcie RSdanych z rekordu wejściowego.
Teraz podczas drukowania rekordu ORSdołączany jest do niego (Output Record Separator), domyślnie jest to nowa linia. Zmieniając ORSspację, wszystkie znaki nowej linii są zamieniane na spacje.
Bardzo podoba mi się to proste rozwiązanie, które jest o wiele bardziej czytelne, niż inne
Fedir RYKHTIK
8
Jeśli ma to większy sens, można to efektywnie zapisać jako: awk 'BEGIN { ORS=" " } { print $0 } END { print "\n"} ' file.txt(dodanie końcowego wiersza tylko w celu zilustrowania początku / końca); „1” oznacza true(przetworzenie linii) i print(wydrukowanie linii). Do tego wyrażenia można również dodać warunkowy, np. Działający tylko na liniach pasujących do wzorca: awk 'BEGIN { ORS=" " } /pattern/ { print $0 } END { print "\n"} '
Michał
2
Możesz to zrobić więcej: codeawk 'ORS = ""' file.txtcode
Udi
Podczas korzystania z awk w ten sposób niestety usuwany jest również ostatni wiersz wiersza w pliku. Zobacz odpowiedź Patrick Dark powyżej na temat używania „tr” w podpowłoce, takiej jak „cat file | echo $ (tr "\ 012" ")" co załatwi sprawę. Fajne
Bernie Reiter
143
gnu sed ma opcję -zdla rekordów (wierszy) oddzielonych od siebie. Możesz po prostu zadzwonić:
Nawet jeśli dane wejściowe zawierają wartości null, zostaną zachowane (jako separatory rekordów).
Toby Speight
6
Czy to nie załaduje całego wejścia, jeśli nie ma wartości zerowych? W takim przypadku przetwarzanie pliku o pojemności wielu gigabajtów może być awarią.
Ruslan
3
@ Ruslan, tak, ładuje całe dane wejściowe. To rozwiązanie nie jest dobrym pomysłem w przypadku plików wielogigabajtowych.
JJoao,
7
To naprawdę najlepsza odpowiedź. Inne wyrażenia są zbyt zniekształcone, aby je zapamiętać. @JJoao Możesz go używać z -u, --unbuffered. Te manstany magiczne: „obciążenie minimalne ilości danych z plików wejściowych i przepłukać bufory wyjściowe częściej”.
Jak wskazano w komentarzach, warto zauważyć, że wprowadzono to zmiany. -i.bakda ci kopię zapasową oryginalnego pliku przed zastąpieniem, na wypadek gdyby twoje wyrażenie regularne nie było tak inteligentne, jak myślałeś.
Proszę przynajmniej wspomnieć, że -ibez przyrostka nie tworzy kopii zapasowej . -i.bakchroni cię przed łatwym, brzydkim błędem (powiedzmy, zapomnieniem -pwpisania i wyzerowaniem pliku).
Telemachus,
6
@Telemachus: To słuszna kwestia, ale można się z nią kłócić. Głównym powodem, o którym nie wspomniałem, jest to, że przykład sed w pytaniu PO nie tworzy kopii zapasowych, więc wydaje się tutaj zbędny. Innym powodem jest to, że tak naprawdę nigdy nie korzystałem z funkcji tworzenia kopii zapasowych (w rzeczywistości uważam, że automatyczne tworzenie kopii zapasowych jest denerwujące), więc zawsze zapominam o tym. Trzecim powodem jest to, że moja linia poleceń wydłuża się o cztery znaki. Na lepsze lub gorsze (prawdopodobnie gorsze) jestem kompulsywnym minimalistą; Po prostu wolę zwięzłość. Zdaję sobie sprawę, że się nie zgadzasz. Postaram się jak najlepiej zapamiętać, aby ostrzegać przed kopiami zapasowymi w przyszłości.
ire_and_curses
6
@Ire_and_curses: Właściwie to byłeś cholernie dobrym argumentem za ignorowaniem mnie. To znaczy, masz powody swoich wyborów i bez względu na to, czy zgadzam się z nimi, z pewnością to szanuję. Nie jestem do końca pewien, dlaczego, ale ostatnio miałem łzy nad tą konkretną rzeczą ( -iflaga w Perlu bez sufiksu). Jestem pewien, że wkrótce znajdę coś innego do obsesji. :)
Telemachus
Naprawdę niefortunne jest to, że nie działa to ze standardowym podaniem -nazwy pliku. Czy jest na to sposób? To mój sposób, aby nie martwić się o modyfikację pliku, używając potoku rozpoczynającego się od cat.
Steven Lu
@StevenLu Perl domyślnie czyta ze STDIN, jeśli nie podano nazw plików. Więc możesz zrobić np.perl -i -p -e 's/\n//' < infile > outfile
ire_and_curses
44
Kto potrzebuje sed? Oto bashsposób:
cat test.txt | while read line; do echo -n "$line "; done
Upvote, zwykle użyłem najwyższej odpowiedzi, ale kiedy przesyłam przez nią / dev / urandom, sed nie będzie drukował, dopóki EOF, a ^ C nie będzie EOF. To rozwiązanie drukuje za każdym razem, gdy widzi nową linię. Dokładnie to, czego potrzebowałem! Dzięki!
Wasilij Sharapov,
1
to dlaczego nie: echo -n `cat days.txt` Z tego postu
Tony
9
@ Tony, ponieważ backticks są przestarzałe, a kot jest zbędny ;-) Użyj: echo $ (<days.txt)
seumasmac
10
Nawet przy użyciu cat: while read line; do echo -n "$line "; done < test.txt. Może się przydać, jeśli problem stanowi podpowłoka.
Carlo Cannas,
5
echo $(<file)wyciska wszystkie białe znaki na jedną spację, nie tylko znaki nowej linii: wykracza to poza to, o co prosi OP.
glenn jackman
27
Aby zastąpić wszystkie nowe wiersze spacjami za pomocą awk, bez wczytywania całego pliku do pamięci:
awk '{printf "%s ", $0}' inputfile
Jeśli chcesz ostatnią nową linię:
awk '{printf "%s ", $0} END {printf "\n"}' inputfile
Możesz użyć znaku innego niż spacja:
awk '{printf "%s|", $0} END {printf "\n"}' inputfile
lub po prostu tr -d '\n'jeśli nie chcesz dodawać spacji
spuder
21
Trzy rzeczy.
tr(lub catitp.) absolutnie nie jest potrzebne. (GNU) sedi (GNU) awk, w połączeniu, mogą wykonać 99,9% dowolnego przetwarzania tekstu, którego potrzebujesz.
stream! = oparty na linii. edto edytor liniowy. sednie jest. Zobacz wykład sed , aby uzyskać więcej informacji na temat różnicy. Większość ludzi myli się sedz tym, że opiera się na liniach, ponieważ domyślnie nie jest zbyt chciwy w dopasowywaniu wzorców dla dopasowań SIMPLE - na przykład podczas wyszukiwania wzorców i zastępowania jednym lub dwoma znakami domyślnie zastępuje tylko przy pierwszym dopasowaniu znajduje (chyba że globalne polecenie określiło inaczej). Nie byłoby nawet globalnego polecenia, gdyby opierało się ono na liniach, a nie na STREAM, ponieważ oceniałoby tylko linie na raz. Spróbuj uruchomić ed; zauważysz różnicę. edjest dość przydatny, jeśli chcesz iterować po określonych liniach (np. w pętli for), ale w większości przypadków po prostu chcesz sed.
Biorąc to pod uwagę,
sed -e '{:q;N;s/\n/ /g;t q}' file
działa dobrze w GNU w sedwersji 4.2.1. Powyższe polecenie zastąpi wszystkie znaki nowej linii spacjami. Pisanie jest brzydkie i trochę kłopotliwe, ale działa dobrze. W {}„s można pominąć, ponieważ są one zawarte wyłącznie w celach Sanity.
Jako osoba, która wie tylko tyle sed, aby zrobić podstawowe rzeczy, muszę powiedzieć, że jest bardziej niż o tym, co można zrobić z sedraczej jak łatwo jest zrozumieć, co się dzieje. Bardzo ciężko mi się pracuje, sedwięc wolę prostsze polecenie, kiedy mogę z niego korzystać.
Nate
Używanie t qjako skoku warunkowego działa ze wzorem podobnym s/\n / /do (łączenie wszystkich linii rozpoczynających się spacją) bez wczytywania całego pliku do pamięci. Przydatne podczas przekształcania plików o wielkości wielu megabajtów.
tekstowe
Artykuł, który podlinkowałeś, nie odzwierciedla tego, co mówisz
hek2mgl,
Jest to prawie 800 razy wolniej niż akceptowana odpowiedź przy dużym nakładzie. Wynika to z działania zastępczego dla każdego wiersza przy coraz większych wejściach.
Subtelna uwaga na temat nomenklatury: znak ten \000jest powszechnie określany jako NUL(jeden L) i NULLjest ogólnie używany, gdy mówi się o zerowym wskaźniku (w C / C ++).
Nie jestem ekspertem, ale myślę sed, że najpierw musisz dołączyć następną linię do przestrzeni wzorów, bij używając „ N”. Z sekcji „Multiline Pattern Space” w „Advanced sed Commands” książki sed & awk (Dale Dougherty i Arnold Robbins; O'Reilly 1997; strona 107 w podglądzie ):
Polecenie Dalej (N) multilinii tworzy wielowierszową przestrzeń wzorcową, czytając nowy wiersz danych wejściowych i dołączając go do zawartości przestrzeni wzorcowej. Oryginalna zawartość przestrzeni wzorów i nowa linia wprowadzania są oddzielone nową linią. Osadzony znak nowej linii można dopasować we wzorach sekwencją zmiany znaczenia „\ n”. W wielowierszowej przestrzeni wzorca metaznak „^” odpowiada pierwszemu znakowi w przestrzeni wzorca, a nie znakowi (znakom) po dowolnej osadzonej nowej linii. Podobnie „$” pasuje tylko do końcowej nowej linii w obszarze wzorców, a nie do żadnych osadzonych nowej linii. Po wykonaniu następnego polecenia kontrola jest następnie przekazywana do kolejnych poleceń w skrypcie.
Od man sed:
[2addr] N
Dołącz następny wiersz danych wejściowych do obszaru wzorców, używając osadzonego znaku nowej linii, aby oddzielić dołączony materiał od oryginalnej zawartości. Zauważ, że bieżący numer linii zmienia się.
Mam używany ten szukać (wielokrotność) źle sformatowane pliki dziennika, w których ciąg wyszukiwania można znaleźć na „osierocone” następnym wierszu.
Zastosowałem podejście hybrydowe, aby ominąć kwestię nowej linii, używając tr do zastąpienia nowej linii tabulatorami, a następnie zamiany tabulacji na cokolwiek chcę. W tym przypadku „ ”, ponieważ próbuję generować podziały HTML.
W systemie Windows prawdopodobnie musisz użyć tr "\n" " " < input. Powłoka systemu Windows (cmd.exe) nie traktuje apostrofu jako cudzysłowu.
Keith Thompson
Nie, w podsystemie Ubuntu systemu Windows 10 musisz użyćtr "\n\r" " " < input.txt > output.txt
użytkownik1491819,
To działa na Windows 10 przy użyciu GnuWin32: cat SourceFile.txt | tr --delete '\r\n' > OutputFile.txt. Lub zamiast Gnuwin32 użyj Gow (Gnu na Windows), github.com/bmatzelle/gow/wiki
Alchemistmatt
5
Rozwiązanie kuloodporne. Bezpieczny dla danych binarnych i zgodny z POSIX, ale powolny.
POSIX sed
wymaga danych wejściowych zgodnie z
plikiem tekstowym POSIX
i
definicjami linii POSIX , więc bajty NULL i zbyt długie linie nie są dozwolone, a każda linia musi kończyć się nową linią (w tym ostatnią linią). Utrudnia to używanie sed do przetwarzania dowolnych danych wejściowych.
Poniższe rozwiązanie pozwala uniknąć sed i zamiast tego konwertuje bajty wejściowe na kody ósemkowe, a następnie ponownie na bajty, ale przechwytuje kod ósemkowy 012 (nowa linia) i wyświetla zamiast niego ciąg zastępczy. O ile wiem, rozwiązanie jest zgodne z POSIX, więc powinno działać na wielu różnych platformach.
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
Obaj read, [i printfsą Zabudowy w co najmniej bash, ale to prawdopodobnie nie jest gwarantowana przez POSIX, więc na niektórych platformach może być, że każdy bajt wejściowy rozpocznie jeden lub więcej nowych procesów, które będą spowolnić. Nawet w trybie bash to rozwiązanie osiąga jedynie około 50 kB / s, więc nie nadaje się do dużych plików.
Testowane na Ubuntu (bash, dash i busybox), FreeBSD i OpenBSD.
Moc skryptowania powłoki polega na tym, że jeśli nie wiesz, jak to zrobić w jeden sposób, możesz to zrobić w inny sposób. I wiele razy masz więcej rzeczy do wzięcia pod uwagę niż skomplikowane rozwiązanie prostego problemu.
Jeśli chodzi o to, że gawk jest powolny ... i wczytuje plik do pamięci, nie wiem tego, ale dla mnie gawk wydaje się działać z jedną linią na raz i jest bardzo bardzo szybki (nie tak szybki jak niektóre inne , ale czas pisania i testowania również się liczy).
Przetwarzam MB, a nawet GB danych, a jedynym ograniczeniem, jakie znalazłem, jest rozmiar linii.
Zastępuje [to spacją i \rspacją oraz \nspacją i ]spacją.tr -d '\r\n' <fileusunie dowolne znaki \rlub \nznaki, ale nie o to też pyta. tr -d '\r' <fileusunie wszystkie \rpostacie (bez względu na to, czy sąsiadują \n), co jest prawdopodobnie bliższe przydatności, a także prawdopodobnie poprawne dla potrzeb PO (wciąż zakładając, że trrozumiesz tę notację odwrotnego ukośnika).
tripleee
4
Możesz użyć xargs- \ndomyślnie zastąpi go spacją.
Miałoby to jednak problemy, gdyby dane wejściowe zawierały jakiś przypadek unterminated quote, np. Jeśli znaki cudzysłowu w danym wierszu nie pasują.
echo "1\n2\n3" | awk '{printf $0}', to działa dla mnie. @ edi9999
Itachi
Masz rację przepraszam, zapomniałem fw printf
edi9999
to było jedyne podejście, które działało dla mnie w ramach git bash dla Windows
Plato
3
W systemie Mac OS X (za pomocą sed FreeBSD):
# 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
Nie musisz uciekać przed cudzysłowami i znakiem dolara, jeśli zmienisz zewnętrzne na pojedyncze cudzysłowy. Litera „o” jest zwykle uważana za zły wybór jako nazwa zmiennej, ponieważ można ją pomylić z cyfrą „0”. Nie musisz także inicjować swojej zmiennej, domyślnie jest to ciąg zerowy. Jednakże, jeśli nie chce się obcych wiodącą miejsca: awk '{s = s sp $0; sp = " "} END {print s}'. Jednak zobacz moją odpowiedź na sposób użycia awk bez wczytywania całego pliku do pamięci.
Wstrzymano do odwołania.
Proszę sprawdzić odpowiedź Thora zamiast. Jest to sposób bardziej efektywny, czytelny i po prostu lepiej za wszelką cenę w porównaniu tego podejścia (chociaż to będzie działać)!
mschilli,
Koleś, rozumiem. Nie muszę przecierać jej w twarz :-) W każdym razie odpowiedź Thora znajduje się wysoko nad stroną (co jest słuszne), więc co cię to obchodzi?
kralyk
3
Rozwiązaniem, które szczególnie mi się podoba, jest dodanie całego pliku w przestrzeni wstrzymania i zastąpienie wszystkich nowych linii na końcu pliku:
$ (echo foo; echo bar) | sed -n 'H;${x;s/\n//g;p;}'
foobar
Jednak ktoś powiedział mi, że przestrzeń wstrzymania może być skończona w niektórych implementacjach sed.
zastąpienie pustym ciągiem w twojej odpowiedzi ukrywa fakt, że zawsze użycie H do dołączenia do przestrzeni wstrzymania oznacza, że przestrzeń wstrzymania rozpocznie się od nowej linii. Aby tego uniknąć, musisz użyć1h;2,$H;${x;s/\n/x/g;p}
Jeff
3
Zastąp nowy znak dowolnym ciągiem i zastąp także ostatni nowy znak
Czyste trrozwiązania można zastąpić tylko jednym znakiem, a czyste sedrozwiązania nie zastępują ostatniego nowego wiersza danych wejściowych. Poniższe rozwiązanie rozwiązuje te problemy i wydaje się bezpieczne dla danych binarnych (nawet w przypadku ustawień regionalnych 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'
Jest to złe, ponieważ spowoduje niechciane wyjście na każdym wejściu zawierającym@
Steven Lu
@StevenLu: Nie, @na wejściu jest OK. Ucieka %ai wraca. Rozwiązanie może jednak nie być w pełni zgodne z POSIX (bajty NULL są niedozwolone, więc nie są dobre dla danych binarnych, a wszystkie wiersze muszą kończyć się znakiem nowej linii, aby dane trwyjściowe nie były naprawdę poprawne).
Håkon A. Hjortland
Ach Widzę, że to naprawiłeś. Trochę zawiłe, co powinno być prostą operacją, ale dobrą pracą.
Steven Lu
3
To sed wprowadza nowe linie po „normalnym” podstawieniu. Najpierw przycina znak nowej linii, następnie przetwarza zgodnie z instrukcjami, a następnie wprowadza nową linię.
Za pomocą sed możesz zastąpić „koniec” linii (nie znak nowej linii) po przycięciu, wybranym ciągiem, dla każdej linii wejściowej; ale sed wyświetli różne linie. Załóżmy na przykład, że chcesz zamienić „koniec linii” na „===” (bardziej ogólne niż zastąpienie pojedynczą spacją):
PROMPT~$ cat <<EOF |sed 's/$/===/g'
first line
second line
3rd line
EOF
first line===
second line===
3rd line===
PROMPT~$
Aby zastąpić znak nowej linii ciągiem, możesz nieefektywnie użyć tr , jak wskazano wcześniej, aby zastąpić znaki nowej linii „specjalnym znakiem”, a następnie użyć sed aby zastąpić ten znak specjalny ciągiem, który chcesz .
Na przykład:
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~$
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.
Przepływ:
Gdy pierwszy wiersz pobierze z wejścia, następuje zamiana, więc 1 przechodzi do miejsca wstrzymania i \ n przychodzi do obszaru wzorców, następnie dołącza miejsce wstrzymania do obszaru wzorców, a następnie wykonuje się podstawienie i usuwa obszar wzorców.
Podczas dokonywania wymiany drugiej linii 2 przechodzi do przestrzeni wstrzymania, a 1 przychodzi do przestrzeni wzorców, następnie Gdołącza przestrzeń wstrzymania do przestrzeni wzorców, a następnie hkopiuje do niej wzór, a następnie zastępuje i usuwa. Ta operacja jest kontynuowana aż do osiągnięcia eof, a następnie wydrukuj dokładny wynik.
Ostrzegamy jednak, że to echo 'Y' | sed 'x;G;1!h;s/\n/X/g;$!d'skutkuje XY.
Spooky
3
Innym GNUsed metoda, prawie tak samo jak Zsolt Botykai „s odpowiedzi , ale ta wykorzystuje sed” mniej często wykorzystywane s y( Transliterate poleceń, co oszczędza) jeden bajt kodu (tylnym g):
sed ':a;N;$!ba;y/\n/ /'
Można by mieć nadzieję, że ydziałałby szybciej niż s(być może przy trprędkościach, 20x szybciej), ale w GNU sed v4.2.2y jest o około 4% wolniejszy niż s.
tr
jest tylko odpowiednim narzędziem do zadania, jeśli zamienisz pojedynczy znak na pojedynczy znak, podczas gdy powyższy przykład pokazuje zamień znak nowej linii spacją .. Więc w powyższym przykładzie tr może działać .. Ale będzie później ograniczać.tr
w odpowiednim narzędziu do pracy, ponieważ pytający chciał zastąpić każdą nową linię spacją, jak pokazano w jego przykładzie. Zastąpienie nowych linii jest wyjątkowo tajemnicze,sed
ale łatwe do wykonaniatr
. To jest częste pytanie. Wykonanie zamiany wyrażenia regularnego nie jest wykonywane przez,tr
ale przezsed
, co byłoby właściwym narzędziem ... na inne pytanie.tr '\012' ' '
zecho
. W przeciwnym razie usuwany jest również ostatni kanał w pliku.tr '\012' ' ' < filename; echo
Zrób sztuczkę.Odpowiedzi:
Użyj tego rozwiązania z GNU
sed
:Spowoduje to odczytanie całego pliku w pętli, a następnie zastąpienie nowego wiersza (ów) spacją.
Wyjaśnienie:
:a
.N
.$!ba
($!
oznacza to, że nie należy tego robić w ostatnim wierszu, ponieważ powinna istnieć jedna końcowa nowa linia).Oto składnia kompatybilna z wieloma platformami, która działa z BSD i OS X
sed
(zgodnie z komentarzem @Benjie ):Jak widać, użycie
sed
tego prostego problemu jest problematyczne. Aby uzyskać prostsze i odpowiednie rozwiązanie, zobacz tę odpowiedź .źródło
sed
zamiast GNUsed
, więc mogą występować pewne subtelne (i niektóre nie tak subtelne) różnice między nimi. Jest to ciągły ból, jeśli pracujesz zarówno na komputerach z systemem OS X, jak i * nix. Zwykle instaluję GNUcoreutils
ifindutils
OS OS i ignoruję wersje BSD.:a
nie jest rejestr, to etykieta oddziału. Jest to celb
polecenia *, który działa jak „goto”. Nazwanie go rejestrem oznacza, że możesz tworzyć lokalizacje pamięci. Istnieją tylko dwa „rejestry”; jedna nazywa się „przestrzenią wstrzymania”, której skrypt nie używa, a druga „przestrzenią wzorców”.N
Polecenie dołącza do nowej linii i i następny wiersz pliku wejściowego do przestrzeni wzorca. [* Możesz mieć wiele etykiet ib
poleceń. Jeśli maszb
polecenie bez dołączonego do niego znaku etykiety, rozgałęzia się ono na końcu skryptu, aby przeczytać następny wiersz i zapętlić ponownie.]sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/ /g'
sed
jest przeznaczony do użycia z danymi wejściowymi opartymi na linii. Chociaż może zrobić to, czego potrzebujesz.Lepszą opcją jest tutaj użycie
tr
polecenia w następujący sposób:lub całkowicie usuń znaki nowego wiersza:
lub jeśli masz wersję GNU (z jej długimi opcjami)
źródło
tr
to często pomijany klejnot do budowy rurociągów.Szybka odpowiedź
sed będzie przechodzić od kroku 1 do 3, aż dojdzie do ostatniej linii, dopasowując wszystkie linie do obszaru wzorów, gdzie sed zastąpi wszystkie \ n znaków
Alternatywy
Wszystkie alternatywy, w przeciwieństwie do sed , nie będą musiały dotrzeć do ostatniej linii, aby rozpocząć proces
z uderzeniem , powoli
z Perl , sed -jak prędkość
z tr , szybszy niż sed , można zastąpić tylko jedną postacią
z wklejaniem , prędkość podobna do tr , można zastąpić tylko jedną postacią
z awk , tr- podobną prędkością
Inne alternatywy, takie jak „echo $ (<plik)”, są powolne, działają tylko na małych plikach i muszą przetworzyć cały plik, aby rozpocząć proces.
Długa odpowiedź od sed FAQ 5.10
5.10 Dlaczego nie mogę dopasować ani usunąć nowego wiersza za pomocą
sekwencji ucieczki \ n ? Dlaczego nie mogę dopasować 2 lub więcej linii za pomocą \ n?
\ N nigdy nie będzie pasować do nowej linii na końcu linii, ponieważ
nowa linia jest zawsze usuwana przed umieszczeniem linii w obszarze
wzorów. Aby wstawić 2 lub więcej linii do przestrzeni wzorów, użyj
polecenia „N” lub czegoś podobnego (takiego jak „H; ...; g;”).
Sed działa w ten sposób: sed odczytuje jedną linię na raz, odcina
kończącą się nową linię , umieszcza to, co pozostało w przestrzeni wzorcowej, w której
skrypt sed może ją adresować lub zmieniać, a gdy
drukowana jest przestrzeń wzorcowa, dodaje nową linię do standardowego wejścia (lub do pliku). Jeśli
przestrzeń wzoru zostanie całkowicie lub częściowo usunięta za pomocą „d” lub „D”,
nowa linia nie jest dodawana w takich przypadkach. Tak więc skrypty lubią
NIGDY nie zadziała, ponieważ końcowy znak nowej linii jest usuwany przed
wstawieniem linii do obszaru wzorów. Aby wykonać powyższe zadania,
użyj jednego z tych skryptów:
Ponieważ wersje sed inne niż GNU sed mają ograniczenia wielkości
bufora wzorców, należy tutaj preferować narzędzie uniksowe „tr”.
Jeśli ostatni wiersz pliku zawiera nową linię, GNU sed doda
tę nową linię do wyniku, ale usunie wszystkie inne, podczas gdy tr doda
usunie wszystkie nowe linie.
Aby dopasować blok dwóch lub więcej wierszy, istnieją 3 podstawowe opcje:
(1) użyj polecenia „N”, aby dodać następny wiersz do obszaru wzorów;
(2) użyj polecenia „H” co najmniej dwukrotnie, aby dołączyć bieżącą linię
do przestrzeni Hold, a następnie pobrać linie z przestrzeni Hold za
pomocą x, g lub G; lub (3) użyj zakresów adresów (patrz sekcja 3.3 powyżej),
aby dopasować linie między dwoma określonymi adresami.
Wybory (1) i (2)
wstawią \ n do przestrzeni wzorców, gdzie można ją adresować według potrzeb ('s / ABC \ nXYZ / alfabet / g'). Jeden przykład
użycia „N” do usunięcia bloku linii pojawia się w sekcji 4.13
(„Jak usunąć blok określonych kolejnych linii?”). Ten
przykład można zmodyfikować, zmieniając polecenie delete na coś
innego, na przykład „p” (drukuj), „i” (wstaw), „c” (zmiana), „a” (dołącz)
lub „s” (zamiennik) .
Choice (3) nie położy \ n do przestrzeni wzorca, ale nie
pasuje do bloku kolejnych wierszy, więc może się okazać, że nie masz
jeszcze potrzebne \ n, aby znaleźć to, czego szukasz. Ponieważ
wersja GNU sed 3.02.80 obsługuje teraz tę składnię:
oprócz tradycyjnych
adresów z zakresu „/ from here /, / to there / {...}” można całkowicie uniknąć użycia \ n.
źródło
tr
był świetnym pomysłem, a ogólny zasięg zapewnia odpowiedź na najwyższym poziomie.paste
... i wszystkich innych!Krótsza alternatywa awk:
Wyjaśnienie
Program awk składa się z reguł składających się z bloków kodu warunkowego, tj .:
Jeśli kod blok zostanie pominięty, domyślnie jest używany:
{ print $0 }
. Zatem1
interpretowany jest jako prawdziwy warunek iprint $0
jest wykonywany dla każdej linii.Podczas
awk
odczytywania danych wejściowych dzieli je na rekordy na podstawie wartościRS
(Separator rekordów), który domyślnie jest nowymawk
wierszem , a zatem domyślnie parsuje dane wejściowe liniowo. Podział obejmuje również usunięcieRS
danych z rekordu wejściowego.Teraz podczas drukowania rekordu
ORS
dołączany jest do niego (Output Record Separator), domyślnie jest to nowa linia. ZmieniającORS
spację, wszystkie znaki nowej linii są zamieniane na spacje.źródło
awk 'BEGIN { ORS=" " } { print $0 } END { print "\n"} ' file.txt
(dodanie końcowego wiersza tylko w celu zilustrowania początku / końca); „1” oznaczatrue
(przetworzenie linii) iprint
(wydrukowanie linii). Do tego wyrażenia można również dodać warunkowy, np. Działający tylko na liniach pasujących do wzorca:awk 'BEGIN { ORS=" " } /pattern/ { print $0 } END { print "\n"} '
code
awk 'ORS = ""' file.txtcode
gnu sed ma opcję
-z
dla rekordów (wierszy) oddzielonych od siebie. Możesz po prostu zadzwonić:źródło
-u, --unbuffered
. Teman
stany magiczne: „obciążenie minimalne ilości danych z plików wejściowych i przepłukać bufory wyjściowe częściej”.Wersja Perla działa w oczekiwany sposób.
Jak wskazano w komentarzach, warto zauważyć, że wprowadzono to zmiany.
-i.bak
da ci kopię zapasową oryginalnego pliku przed zastąpieniem, na wypadek gdyby twoje wyrażenie regularne nie było tak inteligentne, jak myślałeś.źródło
-i
bez przyrostka nie tworzy kopii zapasowej .-i.bak
chroni cię przed łatwym, brzydkim błędem (powiedzmy, zapomnieniem-p
wpisania i wyzerowaniem pliku).-i
flaga w Perlu bez sufiksu). Jestem pewien, że wkrótce znajdę coś innego do obsesji. :)-
nazwy pliku. Czy jest na to sposób? To mój sposób, aby nie martwić się o modyfikację pliku, używając potoku rozpoczynającego się od cat.perl -i -p -e 's/\n//' < infile > outfile
Kto potrzebuje
sed
? Otobash
sposób:źródło
cat
:while read line; do echo -n "$line "; done < test.txt
. Może się przydać, jeśli problem stanowi podpowłoka.echo $(<file)
wyciska wszystkie białe znaki na jedną spację, nie tylko znaki nowej linii: wykracza to poza to, o co prosi OP.Aby zastąpić wszystkie nowe wiersze spacjami za pomocą awk, bez wczytywania całego pliku do pamięci:
Jeśli chcesz ostatnią nową linię:
Możesz użyć znaku innego niż spacja:
źródło
END{ print ""}
jest krótszą alternatywą dla nowej linii końcowej.to polecenie.
Prosty i łatwy w użyciu.
źródło
tr -d '\n'
jeśli nie chcesz dodawać spacjiTrzy rzeczy.
tr
(lubcat
itp.) absolutnie nie jest potrzebne. (GNU)sed
i (GNU)awk
, w połączeniu, mogą wykonać 99,9% dowolnego przetwarzania tekstu, którego potrzebujesz.stream! = oparty na linii.
ed
to edytor liniowy.sed
nie jest. Zobacz wykład sed , aby uzyskać więcej informacji na temat różnicy. Większość ludzi myli sięsed
z tym, że opiera się na liniach, ponieważ domyślnie nie jest zbyt chciwy w dopasowywaniu wzorców dla dopasowań SIMPLE - na przykład podczas wyszukiwania wzorców i zastępowania jednym lub dwoma znakami domyślnie zastępuje tylko przy pierwszym dopasowaniu znajduje (chyba że globalne polecenie określiło inaczej). Nie byłoby nawet globalnego polecenia, gdyby opierało się ono na liniach, a nie na STREAM, ponieważ oceniałoby tylko linie na raz. Spróbuj uruchomićed
; zauważysz różnicę.ed
jest dość przydatny, jeśli chcesz iterować po określonych liniach (np. w pętli for), ale w większości przypadków po prostu chceszsed
.Biorąc to pod uwagę,
działa dobrze w GNU w
sed
wersji 4.2.1. Powyższe polecenie zastąpi wszystkie znaki nowej linii spacjami. Pisanie jest brzydkie i trochę kłopotliwe, ale działa dobrze. W{}
„s można pominąć, ponieważ są one zawarte wyłącznie w celach Sanity.źródło
sed
, aby zrobić podstawowe rzeczy, muszę powiedzieć, że jest bardziej niż o tym, co można zrobić zsed
raczej jak łatwo jest zrozumieć, co się dzieje. Bardzo ciężko mi się pracuje,sed
więc wolę prostsze polecenie, kiedy mogę z niego korzystać.t q
jako skoku warunkowego działa ze wzorem podobnyms/\n / /
do (łączenie wszystkich linii rozpoczynających się spacją) bez wczytywania całego pliku do pamięci. Przydatne podczas przekształcania plików o wielkości wielu megabajtów.Odpowiedź z: etykietą ...
Jak mogę zastąpić znak nowej linii (\ n) za pomocą sed?
... nie działa we Freebsd 7.2 w linii poleceń:
Ale dzieje się tak, jeśli umieścisz skrypt sed w pliku lub użyjesz -e, aby „zbudować” skrypt sed ...
lub ...
Może sed w OS X jest podobny.
źródło
Łatwe do zrozumienia rozwiązanie
Miałem ten problem. Kickerem było to, że potrzebowałem rozwiązania do pracy na BSD (Mac OS X) i GNU (Linux i Cygwin )
sed
oraztr
:Wynik:
(ma końcowy znak nowej linii)
Działa w systemach Linux, OS X i BSD - nawet bez obsługi UTF-8 lub z kiepskim terminalem.
Użyj,
tr
aby zamienić znak nowej linii na inny znak.NULL
(\000
lub\x00
) jest fajny, ponieważ nie wymaga obsługi UTF-8 i prawdopodobnie nie będzie używany.Posługiwać się
sed
aby dopasowaćNULL
Użyj,
tr
aby zamienić dodatkowe nowe linie, jeśli ich potrzebujeszźródło
\000
jest powszechnie określany jakoNUL
(jeden L) iNULL
jest ogólnie używany, gdy mówi się o zerowym wskaźniku (w C / C ++).Możesz użyć xargs :
lub
źródło
xargs < file.txt
Nie jestem ekspertem, ale myślę
sed
, że najpierw musisz dołączyć następną linię do przestrzeni wzorów, bij używając „N
”. Z sekcji „Multiline Pattern Space” w „Advanced sed Commands” książki sed & awk (Dale Dougherty i Arnold Robbins; O'Reilly 1997; strona 107 w podglądzie ):Od
man sed
:Mam używany ten szukać (wielokrotność) źle sformatowane pliki dziennika, w których ciąg wyszukiwania można znaleźć na „osierocone” następnym wierszu.
źródło
Zastosowałem podejście hybrydowe, aby ominąć kwestię nowej linii, używając tr do zastąpienia nowej linii tabulatorami, a następnie zamiany tabulacji na cokolwiek chcę. W tym przypadku „
”, ponieważ próbuję generować podziały HTML.
źródło
W odpowiedzi na powyższe rozwiązanie „tr”, w systemie Windows (prawdopodobnie przy użyciu wersji tr Gnuwin32), proponowane rozwiązanie:
nie działało dla mnie, albo z jakiegoś powodu albo błąd, albo faktycznie zastąpi \ nw / ''.
Używając innej funkcji tr, opcja „usuń” -d działała jednak:
lub „\ r \ n” zamiast „\ n”
źródło
tr "\n" " " < input
. Powłoka systemu Windows (cmd.exe) nie traktuje apostrofu jako cudzysłowu.tr "\n\r" " " < input.txt > output.txt
cat SourceFile.txt | tr --delete '\r\n' > OutputFile.txt
. Lub zamiast Gnuwin32 użyj Gow (Gnu na Windows), github.com/bmatzelle/gow/wikiRozwiązanie kuloodporne. Bezpieczny dla danych binarnych i zgodny z POSIX, ale powolny.
POSIX sed wymaga danych wejściowych zgodnie z plikiem tekstowym POSIX i definicjami linii POSIX , więc bajty NULL i zbyt długie linie nie są dozwolone, a każda linia musi kończyć się nową linią (w tym ostatnią linią). Utrudnia to używanie sed do przetwarzania dowolnych danych wejściowych.
Poniższe rozwiązanie pozwala uniknąć sed i zamiast tego konwertuje bajty wejściowe na kody ósemkowe, a następnie ponownie na bajty, ale przechwytuje kod ósemkowy 012 (nowa linia) i wyświetla zamiast niego ciąg zastępczy. O ile wiem, rozwiązanie jest zgodne z POSIX, więc powinno działać na wielu różnych platformach.
Dokumentacja referencyjna POSIX: sh , język poleceń powłoki , od , tr , grep , read , [ , printf .
Obaj
read
,[
iprintf
są Zabudowy w co najmniej bash, ale to prawdopodobnie nie jest gwarantowana przez POSIX, więc na niektórych platformach może być, że każdy bajt wejściowy rozpocznie jeden lub więcej nowych procesów, które będą spowolnić. Nawet w trybie bash to rozwiązanie osiąga jedynie około 50 kB / s, więc nie nadaje się do dużych plików.Testowane na Ubuntu (bash, dash i busybox), FreeBSD i OpenBSD.
źródło
W niektórych sytuacjach możesz zmienić
RS
na inny ciąg lub znak. W ten sposób \ n jest dostępny dla sub / gsub:Moc skryptowania powłoki polega na tym, że jeśli nie wiesz, jak to zrobić w jeden sposób, możesz to zrobić w inny sposób. I wiele razy masz więcej rzeczy do wzięcia pod uwagę niż skomplikowane rozwiązanie prostego problemu.
Jeśli chodzi o to, że gawk jest powolny ... i wczytuje plik do pamięci, nie wiem tego, ale dla mnie gawk wydaje się działać z jedną linią na raz i jest bardzo bardzo szybki (nie tak szybki jak niektóre inne , ale czas pisania i testowania również się liczy).
Przetwarzam MB, a nawet GB danych, a jedynym ograniczeniem, jakie znalazłem, jest rozmiar linii.
źródło
Jeśli jesteś nieszczęśliwy na tyle, aby poradzić sobie z zakończeniami linii systemu Windows, musisz usunąć
\r
i\n
źródło
[
to spacją i\r
spacją oraz\n
spacją i]
spacją.tr -d '\r\n' <file
usunie dowolne znaki\r
lub\n
znaki, ale nie o to też pyta.tr -d '\r' <file
usunie wszystkie\r
postacie (bez względu na to, czy sąsiadują\n
), co jest prawdopodobnie bliższe przydatności, a także prawdopodobnie poprawne dla potrzeb PO (wciąż zakładając, żetr
rozumiesz tę notację odwrotnego ukośnika).Możesz użyć
xargs
-\n
domyślnie zastąpi go spacją.Miałoby to jednak problemy, gdyby dane wejściowe zawierały jakiś przypadek
unterminated quote
, np. Jeśli znaki cudzysłowu w danym wierszu nie pasują.źródło
Znajduje i zamienia za pomocą zezwolenia \ n
Staje się
źródło
Dlaczego nie znalazłem prostego rozwiązania
awk
?printf
wypisze każdą linię bez nowych linii, jeśli chcesz oddzielić oryginalne linie spacją lub inną:źródło
echo "1\n2\n3" | awk '{printf $0}'
, to działa dla mnie. @ edi9999f
w printfW systemie Mac OS X (za pomocą sed FreeBSD):
źródło
Aby usunąć puste linie:
źródło
sed: 1: "s/^$//;t;p;": undefined label ';p;'
.Za pomocą Awk:
źródło
awk '{s = s sp $0; sp = " "} END {print s}'
. Jednak zobacz moją odpowiedź na sposób użycia awk bez wczytywania całego pliku do pamięci.Rozwiązaniem, które szczególnie mi się podoba, jest dodanie całego pliku w przestrzeni wstrzymania i zastąpienie wszystkich nowych linii na końcu pliku:
Jednak ktoś powiedział mi, że przestrzeń wstrzymania może być skończona w niektórych implementacjach sed.
źródło
1h;2,$H;${x;s/\n/x/g;p}
Zastąp nowy znak dowolnym ciągiem i zastąp także ostatni nowy znak
Czyste
tr
rozwiązania można zastąpić tylko jednym znakiem, a czystesed
rozwiązania nie zastępują ostatniego nowego wiersza danych wejściowych. Poniższe rozwiązanie rozwiązuje te problemy i wydaje się bezpieczne dla danych binarnych (nawet w przypadku ustawień regionalnych UTF-8):Wynik:
źródło
@
@
na wejściu jest OK. Ucieka%a
i wraca. Rozwiązanie może jednak nie być w pełni zgodne z POSIX (bajty NULL są niedozwolone, więc nie są dobre dla danych binarnych, a wszystkie wiersze muszą kończyć się znakiem nowej linii, aby danetr
wyjściowe nie były naprawdę poprawne).To sed wprowadza nowe linie po „normalnym” podstawieniu. Najpierw przycina znak nowej linii, następnie przetwarza zgodnie z instrukcjami, a następnie wprowadza nową linię.
Za pomocą sed możesz zastąpić „koniec” linii (nie znak nowej linii) po przycięciu, wybranym ciągiem, dla każdej linii wejściowej; ale sed wyświetli różne linie. Załóżmy na przykład, że chcesz zamienić „koniec linii” na „===” (bardziej ogólne niż zastąpienie pojedynczą spacją):
Aby zastąpić znak nowej linii ciągiem, możesz nieefektywnie użyć tr , jak wskazano wcześniej, aby zastąpić znaki nowej linii „specjalnym znakiem”, a następnie użyć sed aby zastąpić ten znak specjalny ciągiem, który chcesz .
Na przykład:
źródło
Możesz także użyć tej metody
Wyjaśnienie
Przepływ:
Gdy pierwszy wiersz pobierze z wejścia, następuje zamiana, więc 1 przechodzi do miejsca wstrzymania i \ n przychodzi do obszaru wzorców, następnie dołącza miejsce wstrzymania do obszaru wzorców, a następnie wykonuje się podstawienie i usuwa obszar wzorców.
Podczas dokonywania wymiany drugiej linii 2 przechodzi do przestrzeni wstrzymania, a 1 przychodzi do przestrzeni wzorców, następnie
G
dołącza przestrzeń wstrzymania do przestrzeni wzorców, a następnieh
kopiuje do niej wzór, a następnie zastępuje i usuwa. Ta operacja jest kontynuowana aż do osiągnięcia eof, a następnie wydrukuj dokładny wynik.źródło
echo 'Y' | sed 'x;G;1!h;s/\n/X/g;$!d'
skutkujeXY
.Innym GNU
sed
metoda, prawie tak samo jak Zsolt Botykai „s odpowiedzi , ale ta wykorzystujesed
” mniej często wykorzystywane sy
( Transliterate poleceń, co oszczędza) jeden bajt kodu (tylnymg
):Można by mieć nadzieję, że
y
działałby szybciej niżs
(być może przytr
prędkościach, 20x szybciej), ale w GNU sed v4.2.2y
jest o około 4% wolniejszy niżs
.Bardziej przenośna wersja BSD
sed
:źródło
y
jest o około 15% szybszy. Zobacz tę odpowiedź na działający przykład.sed -e ':a' -e 'N;$!ba' -e 'y/\n/ /'
byłby to właściwy sposób.