sed nie daje mi poprawnej operacji zastępczej dla newline z Mac-różnice między GNU sed i BSD / OSX sed [duplikat]

To pytanie ma już odpowiedź tutaj:

Używam tego odniesienia: sed help: dopasowanie i zastąpienie dosłownego "\n " (nie nowej linii)

I mam plik " test1.txt", który zawiera łańcuch hello\ngoodbye

Używam tego polecenia do wyszukiwania i zamiany "\n " na rzeczywiste znaki nowej linii:

sed -i '' 's/\\n/\n/g' test1.txt

Ale wynik jest: hellongoodbye. zastępuje tylko "\n "przez " n", A nie rzeczywistą nową linię. To samo robi z /t, gdzie zostawia" t", a nie zakładkę.

" jest dla niezdefiniowanego błędu w MAC: http://mpdaugherty.wordpress.com/2010/05/27/difference-with-sed-in-place-editing-on-mac-os-x-vs-linux/

Update :

Próbowałem obu komend, które @hek2mgl "suggested": {]}

sed -i 's/\\n/\n/g' test.txt
# Or:
sed -i'' 's/\\n/\n/g' test.txt

Chociaż mogą pracować z Linuksem, z MAC OS mam następujący błąd:

sed: 1: "test1.txt": undefined label 'est1.txt'
Nie wiem, dlaczego nie mogę tego uruchomić. Z góry dzięki.
Author: Community, 2014-06-18

2 answers

W przypadku BSD/macOS sed, aby użyć nowego wiersza zastępczego ciągu wywołania funkcji s, musisz użyć \-Escape rzeczywista newline - Sekwencja escape \n jest nie wspierana tam (w przeciwieństwie do regex część rozmowy).

  • albo : po prostu wstaw rzeczywisty newline:

    sed -i '' 's/\\n/\
    /g' test1.txt
    
  • Or : use an ANSI C-quoted string ($'...') do splicingu w newline ($'\n'; działa w bash, ksh, lub zsh):

    sed -i '' 's/\\n/\'$'\n''/g' test1.txt
    

GNU sed, natomiast rozpoznaje w ciągach zastępczych; Czytaj dalej, aby uzyskać obszerny przegląd różnic między tymi dwiema implementacjami.


Różnice pomiędzy GNU sed (Linux) a BSD / macOS sed

macOS używa wersji BSD sed[1], które różni się pod wieloma względami od GNU sed wersja, która pochodzi z Linux DISTRO.

Ich wspólny mianownik to funkcjonalność określona przez POSIX : zobacz spec POSIX sed.

Najbardziej przenośnym podejściem jest używanie tylko funkcji POSIX , które jednak ogranicza funkcjonalność :

  • w szczególności, POSIX określa wsparcie tylko dla podstawowe wyrażenia regularne, które mają wiele ograniczeń (np. brak wsparcia dla | (alternacja) w ogóle, brak bezpośredniego wsparcia dla + i ?) i różne wymagania specjalne.
    • Zastrzeżenie: GNU sed (bez -r), czy obsługuje \|, \+ i \?, które nie są zgodne ze standardem POSIX; użyj --posix, aby wyłączyć (patrz poniżej).
  • aby używać tylko funkcji POSIX :
    • (obie wersje): należy używać tylko opcji -n i -e (w szczególności nie należy używać -E lub -rdo włączania obsługi rozszerzonych wyrażeń regularnych)
    • GNU sed: Dodaj opcjÄ ™ --posix aby zapewniÄ ‡ funkcjonalnoĹ "Ä ‡ tylko w standardzie POSIX (nie jest to absolutnie potrzebne, ale bez niej moĹźna byĹ' oby nieumyślnie uĺźywaä ‡ funkcji innych niż POSIX, nie zwracajÄ ... c uwagi; zastrzeżenie: --posix nie jest to zgodne z POSIX)
    • używanie tylko funkcji POSIX oznacza surowsze wymagania formatowania (rezygnacja z wielu udogodnień dostępnych w GNU sed):
      • sekwencje znaków sterujących, takie jak \n i \t, na ogół nie są obsługiwane.
      • etykiety i polecenia rozgałęziające (np., b) musi następować rzeczywista nowa linia lub kontynuacja poprzez oddzielną opcję -e.
      • zobacz poniżej szczegóły.

Jednak obie wersje implementacja rozszerzeń do standardu POSIX:

  • czym rozszerzenia implementują różnią się (GNU sed implementuje więcej).
  • nawet te rozszerzenia one oba implementują częściowo różnią się składnią.

Jeśli potrzebujesz wspierać obie platformy (omówienie różnic):

  • Niekompatybilne funkcje:
    • użycie na -i opcja bez argument (in-place update without backup) jest niezgodny:
      • BSD sed: musi używać -i ''
      • GNU sed: musi używać tylko -i (odpowiednik: -i'') - używanie -i '' nie działa.
    • -i sensownie włącza per-input-file numeracja linii w GNU sed i najnowsze wersje BSD sed (np. na FreeBSD 10), ale czy Nie na macOS od 10.12.
      Należy pamiętać, że w przypadku braku -i wszystkie wersje numerują linie łącznie pomiędzy Plikami wejściowymi.
    • jeśli ostatnia linia wejściowa ma nie ma końcową nową linię (i jest drukowana):
      • BSD sed: zawsze dodaje nową linię na wyjściu, nawet jeśli linia wejściowa nie kończy się na niej.
      • GNU sed: zachowuje status wątku końcowego-newline , tzn. dopisuje nową linię tylko wtedy, gdy linia wejściowa kończy się na jednej.
  • wspólne cechy:
    • jeśli ograniczysz swoje skrypty sed do tego, co obsługuje BSD sed, będą one również działać w GNU sed - z zauważalnym wyjątkiem używania specyficznych dla platformy rozszerzonych funkcji regex z-E. Oczywiście zrezygnujesz także z rozszerzeń, które są specyficzne dla wersji GNU. Zobacz następny sekcja.

W 2004 roku, w ramach projektu, w ramach projektu, w ramach projektu, stworzono nową wersję systemu operacyjnego dla systemu operacyjnego Linux, która miała zostać wdrożona w 2006 roku.]}

zauważ, że używam skrótów macOS i Linux odpowiednio dla wersji BSD i GNU sed, ponieważ są to wersje zapasowe na każdej platformie. Można jednak zainstalować GNU sed na macOS, na przykład za pomocą Homebrew z brew install gnu-sed.

Uwaga: z wyjątkiem sytuacji, gdy używane są flagi -r i -E (rozszerzone wyrażenia regularne), poniższe instrukcje stanowią zapis zgodny z POSIX sed Skrypty.

  • dla zgodności z POSIX, musisz ograniczyć się do POSIX BREs ( podstawowe wyrażenia regularne) , które są, niestety, jak sama nazwa wskazuje, dość podstawowe.
    Zastrzeżenie : nie zakładaj, że \|, \+ i \? są obsługiwane: podczas gdy GNU sed je obsługuje (chyba że użyto --posix), BSD sed nie - te funkcje nie są zgodne z POSIX.
    While \+ oraz \? można emulować w sposób zgodny z POSIX:
    \{1,\} na \+,
    \{0,1\} na \?,
    \| (alternation) cannot, niestety.
  • Dla potężniejszych wyrażenia regularne, użyj -E (zamiast -r) do obsługi EREs ( rozszerzone wyrażenia regularne) (GNU sed nie dokumentuje -E, ale działa tam jako alias -r; nowsza wersja BSD sed, taka jak na FreeBSD 10, teraz również obsługuje -r, ale wersja macOS od 10.10 nie nie ).
    Zastrzeżenie : mimo że użycie -r / -E oznacza, że Twoje polecenie jest z definicji , a nie Zgodny z POSIX, musisz jednak ograniczyć się do POSIX EREs (rozszerzone wyrażenia regularne). Niestety, oznacza to, że nie będziesz w stanie użyć kilku użytecznych konstrukcji, w szczególności: [176]}

    • twierdzenia o granicach słów, ponieważ są specyficzne dla platformy (np. \< na Linuksie, [[:<]] na OS X).
    • back-references wewnątrz wyrażeń regularnych (W przeciwieństwie do "back-references" do przechwytywania grup w zastępstwie string of s function calls), ponieważ BSD sed nie obsługuje ich w Extended regexes (ale, co ciekawe, robi to w basic , gdzie są wymagane POSIX).
  • Sekwencje ucieczki znaków sterujących, takie jak \n i \t:

    • w wyrażeniach regularnych (zarówno we wzorcach wyboru, jak i pierwszym argumencie funkcji s), Załóżmy, że tylko \n jest rozpoznawana jako sekwencja escape (rzadko używany, ponieważ przestrzeń wzorca jest zwykle pojedynczą linią (bez kończenia \n), ale nie wewnątrz klasy znaków, tak że np. [^\n] nie działa; (jeśli wejście nie zawiera znaków sterujących. inne niż \t, można emulować [^\n] za pomocą [[:print:][:blank:]]; w przeciwnym razie znaki sterujące splice. w as literały[2]) - zazwyczaj, zawierać znaki kontrolne jako literały , albo poprzez spliced-in ANSI C-cytowane ciągi (np., $'\t') w powłokach, które go obsługują (bash, ksh, zsh), lub poprzez zastępowanie poleceń za pomocą printf (np., "$(printf '\t')").
      • tylko dla Linuksa:
        sed 's/\t/-/' <<<$'a\tb' # -> 'a-b'
      • macOS i Linux:
        sed 's/'$'\t''/-/' <<<$'a\tb' # ANSI C-quoted string
        sed 's/'"$(printf '\t')"'/-/' <<<$'a\tb' # command subst. with printf
    • W ciągach zastępczych używanych z poleceniem s, zakładają, że nie są obsługiwane żadne sekwencje ucieczki znaków sterujących, więc ponownie dołączają znaki sterujące. jako literały , jak wyżej.

      • tylko dla Linuksa:
        sed 's/-/\t/' <<<$'a-b' # -> 'a<tab>b'
      • macOS i Linux:
        sed 's/-/'$'\t''/' <<<'a-b'
        sed 's/-/'"$(printf '\t')"'/' <<<'a-b'
    • Ditto dla argumentów tekstowych do i And a functions: nie używaj sekwencji znaków sterujących - patrz poniżej.

  • etykiety i rozgałęzienia: etykiety oraz argument label-name do funkcji b i t musi być poprzedzone przez literal newline lub spliced-in $'\n'. Alternatywnie, użyj wielu opcji -e i zakończ każde prawo po nazwie etykiety.
    • tylko dla Linuksa:
      sed -n '/a/ bLBL; d; :LBL p' <<<$'a\nb' # -> 'a'
    • macOS i Linux:
      • EITHER (actual newlines):
        sed -n '/a/ bLBL d; :LBL p' <<<$'a\nb'
      • or (spliced-in $\n instancje):
        sed -n '/a/ bLBL'$'\n''d; :LBL'$'\n''p' <<<$'a\nb'
      • OR (multiple -e opcje):
        sed -n -e '/a/ bLBL' -e 'd; :LBL' -e 'p' <<<$'a\nb'
  • funkcje i i a do wstawiania / dodawania tekstu: po nazwie funkcji przez \, a następnie przez literal newline lub spliced-in $'\n' przed podaniem argumentu tekstowego.
    • tylko dla Linuksa:
      sed '1 i new first line' <<<$'a\nb' # -> 'new first line<nl>a<nl>b'
    • macOS i Linux:
      sed -e '1 i\'$'\n''new first line' <<<$'a\nb'
    • Uwaga:
      • bez -e argument tekstowy jest niewytłumaczalny nie newline-zakończone na wyjściu w macOS (błąd?).
      • nie używaj znaków kontrolnych , takich jak \n i \t w argumencie tekstowym, ponieważ są one obsługiwane tylko w Linuksie.
      • jeśli argument tekstowy ma wewnętrzne nowe linie, \-unikaj ich.
      • jeśli chcesz umieścić dodatkowe polecenia po argumencie tekstowym, musisz zakończyć go znakiem nowego wiersza (literalnym lub połączonym) lub kontynuować oddzielną opcją -e (jest to ogólny wymóg, który dotyczy wszystkich wersji).
  • wewnątrz funkcja listy (wiele wywołań funkcji zamkniętych w {...}), należy również zakończyć funkcję last , przed zamknięciem }, z ;.
    • tylko dla Linuksa:
    • sed -n '1 {p;q}' <<<$'a\nb' # -> 'a'
    • macOS i Linux:
    • sed -n '1 {p;q;}' <<<$'a\nb'

GNU sed - Cechy szczególne brakuje w BSD sed razem:

Funkcje GNU, których przegapisz, jeśli potrzebujesz wspierać obie platformy:


[1] wersja macOS sed jest starsza niż wersja na innych systemach podobnych do BSD, takich jak FreeBSD i PC-BSD. Niestety, oznacza to, że nie można zakładać, że funkcje, które działają w FreeBSD, na przykład, będą działać [to samo] na macOS.

[2] cytowany ciąg znaków $'\001\002\003\004\005\006\007\010\011\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\177' ANSI C zawiera wszystkie znaki kontrolne ASCII oprócz \n (i NUL), więc można go używać w połączeniu z [:print:] dla dość solidnej emulacji [^\n]:
'[[:print:]'$'\001\002\003\004\005\006\007\010\011\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\177'']

 55
Author: mklement0,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-06 03:32:03

To może wydawać się trochę dziwne, ale spróbuj:

sed -i '' 's/\\n/\
/g' test1.txt

Tj. użyj rzeczywistej nowej linii zamiast \n.

Wyjaśnienie jest takie, że masz dziwne sed! Szczegółowe informacje można znaleźć w podręczniku Mac sed: https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/sed.1.html

W opisie komendy s jest napisane:

A line can be split by substituting a newline character into it.  To specify
a newline character in the replacement string, precede it with a backslash.

Również w opisie opcji -i jest napisane, że rozszerzenie nie jest opcjonalne, i że jeśli nie chcesz, musisz podać pusty argument. Więc wszystko ma sens w końcu!

 5
Author: ooga,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-18 01:01:07