Może to być bardzo podstawowe pytanie, ale nie jestem w stanie utworzyć sed na liniowce.

Rozważ tę linię

foo@some_text/48183 bar@another-test/22787 xyz@some_another_text/2291

Chcę zastąpić wszystko z "@", aby przestrzenić oddzielone przecinkiem. Więc moja oczekiwana wydajność powinna wyglądać

foo,bar,xyz

Próbowałem zastąpić sed -e 's/@.*[^ ]/,/g'

Każda pomoc zostanie doceniona.

4
g_p 4 czerwiec 2018, 10:24

4 odpowiedzi

Najlepsza odpowiedź

Możesz znaleźć i przechwytywać dowolne 1+ znaki inne niż @ przed @ char, a następnie dopasuj @ i dowolne 0+ znaki inne niż białe znaki, a następnie za pomocą 0+ Whitespace Chars i zastąp wszystkie to z zastępczem do grupy 1 i przecinka. Następnie będziesz musiał usunąć przecinek końcowy.

Zobacz a SED DEMO:

s='foo@some_text/48183 bar@another-test/22787 xyz@some_another_text/2291'
echo "$s" | sed -E 's/([^@]+)@[^[:space:]]*[[:space:]]*/\1,/g' | sed 's/,$//'

Zauważ, że możesz również użyć sed 's/\([^@][^@]*\)@[^[:space:]]*[[:space:]]*/\1,/g' Idead w wersji Posix Ere. W BRE Posix należy uciec ( i ) i ), aby utworzyć grupę przechwytywania, a + Enctifier powinien zostać usunięty lub zastąpiony konstrukcją aa*.

Szczegóły

  • ([^@]+) - Chwytanie grupy 1: 1+ inne niż @
  • @ - znak @
  • [^[:space:]]* - 0+ znaki inne niż białe znaki
  • [[:space:]]* - 0+ Whitespace znak

\1 jest symbolem zastępczym tekstem przechwytywanym z grupą przechwytywania # 1.

Drugi sed 's/,$//' służy do usuwania ciągnięcia {X1}} na końcu ciągu.

3
Wiktor Stribiżew 4 czerwiec 2018, 07:36

Podstawowy problem z częścią meczowej regexa ({x0}}) jest to .* pasuje do prawie całego odpoczynku łańcucha źródłowego po pierwszej {x2}} (Dość powszechny błąd) i [^ ] pasuje do ostatniego space CAR.

Jeśli używasz @\S+\s* jako część meczu, a następnie {x1}} pasuje do części "nie space" (np. some_text/48183) i \s* Mecze od tego czasu pomieszczenia opcjonalne.

Ta wymiana daje foo,bar,xyz,, więc powinieneś w jakiś sposób usunąć ostatni przecinek.

2
Valdi_Bo 4 czerwiec 2018, 07:49

Po awk może ci pomóc tutaj.

awk 'BEGIN{OFS=","}{for(i=1;i<=NF;i++){sub(/@.*/,"",$i)}} 1'  Input_file

rozwiązanie 2ND: biorąc kod z poczty Wiktor Stribizew i modyfikowanie go trochę do konwersji do jednego {x0}} teraz.

sed -E 's/([^@]+)@[^[:space:]]*[[:space:]]*/\1,/g;s/,$//'  Input_file
2
RavinderSingh13 4 czerwiec 2018, 07:59

Możesz także zrobić to na odwrót, nawet jeśli może być nieco więcej pipy.

$ echo "foo@some_text/48183 bar@another-test/22787 xyz@some_another_text/2291" | (tr ' ' ',' | grep -oP '(?=,|^)[^@]+' | tr -d '\n'; echo "")
foo,bar,xyz

Zamiast wymiany, część ciągu można bezpośrednio wyodrębnić odpowiednie części.

Objaśnienia:

  • tr ' ' ',' Aby zastąpić wszystkie przestrzenie przez przecinki.
  • grep -oP '(?=,|^)[^@]+' Aby pobrać wszystko przed @. Wykorzystuje REGEX PERL z Lookaround (nakładając ograniczenie, że poprzedni znak jest przecinkiem lub początkiem ciągu i zaakceptuj wszystkie znaki z wyjątkiem @.
  • tr -d '\n' służy do usuwania EOL włożonego przez grep
  • echo "" może zostać pominięty, jeśli nie musisz mieć zakończenia \n. Następnie możesz uprościć polecenie w tr ' ' ',' | grep -oP '(?=,|^)[^@]+' | tr -d '\n'
2
Allan 4 czerwiec 2018, 08:06