Jak zamienić ciągi zawierające ukośniki na sed?

147

Mam projekt Visual Studio, który jest rozwijany lokalnie. Pliki kodu należy wdrożyć na serwerze zdalnym. Jedynym problemem jest to, że adresy URL, które zawierają, są zakodowane na stałe.

Projekt zawiera adresy URL, takie jak ? Page = one . Aby link był ważny na serwerze, musi to być / page / one .

Zdecydowałem się zastąpić wszystkie adresy URL w moich plikach kodowych sedem przed wdrożeniem, ale utknąłem na ukośnikach.

Wiem, że to nie jest ładne rozwiązanie, ale to proste zaoszczędziłoby mi dużo czasu. Całkowita liczba ciągów, które muszę wymienić, jest mniejsza niż 10. Całkowita liczba plików do sprawdzenia to ~ 30.

Przykład opisujący moją sytuację znajduje się poniżej:

Polecenie, którego używam:

sed -f replace.txt < a.txt > b.txt

replace.txt, który zawiera wszystkie ciągi:

s/?page=one&/pageone/g
s/?page=two&/pagetwo/g
s/?page=three&/pagethree/g

a.txt:

?page=one&
?page=two&
?page=three&

Zawartość b.txt po uruchomieniu komendy sed:

pageone
pagetwo
pagethree

Co chcę, aby plik b.txt zawierał:

/page/one
/page/two
/page/three
afaf12
źródło
1
możliwy duplikat seda wyszukuje i zamienia ciągi zawierające /
Damien MATHIEU
3
możliwy duplikat użycia ukośników w zamianie
seda

Odpowiedzi:

274

Najprostszym sposobem byłoby użycie innego separatora w wierszach wyszukiwania / zamiany, np .:

s:?page=one&:pageone:g

Możesz użyć dowolnego znaku jako separatora, który nie jest częścią żadnego ciągu. Lub możesz uciec z ukośnikiem odwrotnym:

s/\//foo/

Który zastąpiłby /z foo. Chciałbyś użyć odwrotnego ukośnika ze znakiem ucieczki w przypadkach, gdy nie wiesz, jakie znaki mogą wystąpić w łańcuchach zastępczych (na przykład jeśli są to zmienne powłoki).

czai się
źródło
1
> Lub możesz uciec przed tym ukośnikiem odwrotnym. Przykład tego byłby bardziej przydatny, ponieważ nie zawsze wiesz, jakie znaki są w ciągu, aby móc wybrać coś innego. np. to: echo / | sed s / \ // a / g nie działa: sed: -e wyrażenie # 1, char 5: nieznana opcja dla `s '
Max Waterman
1
Czy mógłbyś wtedy dodać jeden? Dzięki :) Znalazłem otoczenie w podwójnych cudzysłowach wydaje się działać: echo / | sed "s / \ // a / g"
Max Waterman
@MaxWaterman to standardowa procedura operacyjna, gdy sedpolecenie regex jest umieszczone w podwójnych cudzysłowach. Nie użyłem ich w mojej odpowiedzi, ponieważ nie pokazałem całej sedlinii poleceń, ale tylko sedciąg polecenia regex, tak jak zrobił to OP. Jeśli umieścisz go w pliku, tak jak zrobił to OP, nie potrzebujesz cudzysłowów.
lurker
Tak, w porządku (choć być może można o tym wspomnieć). Ten przykład pomaga. Odkryłem, że czasami muszę włożyć wiele, wiele odwrotnych ukośników ... i robi się to naprawdę zagmatwane. np. -e "s / '/ \\\\\\\ & / g" Myślę, że tekst jest nieprawidłowy, chociaż: "Który zamieniłby \ na foo" - powinno brzmieć "Który zastąpiłby / na foo", nie?
Max Waterman,
@MaxWaterman dzięki za złapanie tego na \ vs. /. Naprawione. Jeśli masz sedpolecenie w skrypcie powłoki, może być potrzebnych więcej odwrotnych ukośników (każdy lewy ukośnik musi być ponownie odwrócony).
lurker
105

sPolecenia można użyć dowolnego znaku jako separatora; dowolny znak pojawiający się po znaku s. Zostałem wychowany, aby używać #. Tak jak to:

s#?page=one&#/page/one#g
Tom Anderson
źródło
5
Strona podręcznika dla seda BSD na OS X mówi o poleceniu s : Zastąp ciąg zastępujący dla pierwszego wystąpienia wyrażenia regularnego w przestrzeni wzorców. Dowolny znak inny niż ukośnik odwrotny lub nowa linia może być użyty zamiast ukośnika do oddzielenia RE i zamiany. Założę się, że na stronie podręcznika systemowego GNU sed jest coś podobnego.
Tom Anderson,
Aktualnie przyjęta odpowiedź jest w zasadzie taka sama jak ta i została opublikowana minutę wcześniej!
Tom Anderson,
61

Bardzo przydatnym, ale mniej znanym faktem dotyczącym seda jest to, że znane s/foo/bar/polecenie może używać dowolnej interpunkcji, a nie tylko ukośników. Powszechną alternatywą jest to s@foo@bar@, że staje się oczywiste, jak rozwiązać twój problem.

John Zwinck
źródło
Genialna rada, gdy chcesz zastąpić ukośniki. Dzięki!
mbb
9

dodaj \ przed znakami specjalnymi:

s/\?page=one&/page\/one\//g

itp.

Ilja
źródło
4
Mogłem coś przeoczyć, ale próbowałem tego i wygląda na to, że nie działa. Wydawało się to oczywistą rzeczą, aby spróbować, ale zakładając, że mam rację i rzeczywiście nie działa, po co to publikować?
codenoob
4
@codenoob (i każdy, kto tu dotrze) - wymagane jest „s” na początku. s/foo\/bar/foo_bar/zadziała, ale /foo\/bar/foo_bar/nie zadziała.
MynockSpit
5

W systemie, który tworzę, ciąg znaków do zastąpienia przez sed jest tekstem wejściowym od użytkownika, który jest przechowywany w zmiennej i przekazywany do seda.

Jak wspomniano wcześniej w tym poście, jeśli ciąg zawarty w bloku poleceń sed zawiera rzeczywisty separator używany przez sed - to sed kończy się z powodu błędu składniowego. Rozważmy następujący przykład:

To działa:

$ VALUE=12345
$ echo "MyVar=%DEF_VALUE%" | sed -e s/%DEF_VALUE%/${VALUE}/g
MyVar=12345

To się psuje:

$ VALUE=12345/6
$ echo "MyVar=%DEF_VALUE%" | sed -e s/%DEF_VALUE%/${VALUE}/g
sed: -e expression #1, char 21: unknown option to `s'

Zastąpienie domyślnego separatora nie jest w moim przypadku solidnym rozwiązaniem, ponieważ nie chciałem ograniczać użytkownikowi możliwości wprowadzania określonych znaków używanych przez seda jako separatora (np. „/”).

Jednak zastąpienie dowolnego wystąpienia separatora w ciągu wejściowym rozwiązałoby problem. Rozważ poniższe rozwiązanie polegające na systematycznym unikaniu znaku ogranicznika w ciągu wejściowym przed przeanalizowaniem go przez sed. Takie ucieczki można zaimplementować jako zamiennik przy użyciu samego seda, to zastąpienie jest bezpieczne, nawet jeśli ciąg wejściowy zawiera ogranicznik - dzieje się tak, ponieważ ciąg wejściowy nie jest częścią bloku poleceń sed:

$ VALUE=$(echo ${VALUE} | sed -e "s#/#\\\/#g")
$ echo "MyVar=%DEF_VALUE%" | sed -e s/%DEF_VALUE%/${VALUE}/g
MyVar=12345/6

Przekonwertowałem to na funkcję, która ma być używana przez różne skrypty:

escapeForwardSlashes() {

     # Validate parameters
     if [ -z "$1" ]
     then
             echo -e "Error - no parameter specified!"
             return 1
     fi

     # Perform replacement
     echo ${1} | sed -e "s#/#\\\/#g"
     return 0
}
Yoav Drori
źródło
1
Wyciągnięciem z twojej odpowiedzi było dla mnie to, że jeśli WARTOŚĆ, której używasz do zastąpienia DEF_VALUE, ma w sobie ukośniki, to musisz je uciec z 3 ukośnikami odwrotnymi, aby sed działał, np.VALUE="01\\\/01\\\/2018"
alexkb
3

ta linia powinna działać dla Twoich 3 przykładów:

sed -r 's#\?(page)=([^&]*)&#/\1/\2#g' a.txt
  • Kiedyś -r, aby zaoszczędzić trochę ucieczkę.
  • wiersz powinien być ogólny dla jednego, dwóch trzech przypadków. nie musisz robić sub 3 razy

przetestuj na swoim przykładzie (a.txt):

kent$  echo "?page=one&
?page=two&
?page=three&"|sed -r 's#\?(page)=([^&]*)&#/\1/\2#g'
/page/one
/page/two
/page/three
Kent
źródło
1

replace.txt Powinien być

s/?page=/\/page\//g
s/&//g
Ion Cojocaru
źródło
1

Świetna odpowiedź od Anonimowego. \ rozwiązałem mój problem, gdy próbowałem uniknąć cudzysłowów w łańcuchach HTML.

Więc jeśli używasz seda do zwrócenia niektórych szablonów HTML (na serwerze), użyj podwójnego odwrotnego ukośnika zamiast pojedynczego:

var htmlTemplate = "<div style=\\"color:green;\\"></div>";
Sirar Salih
źródło
1

sedjest s TREAM ed itor , w których można użyć |(rury) do wysyłania standardowych strumieni (stdin i stdout konkretnie) przez sedi zmieniać je programowo w locie, co czyni go przydatnym narzędziem w tradycji filozofii Unix; ale może również edytować pliki bezpośrednio, używając -iparametru wymienionego poniżej.
Weź pod uwagę następujące kwestie :

sed -i -e 's/few/asd/g' hello.txt

s/stosuje się S ubstitute znaleziony ekspresji fewz asd:

Nieliczni, odważni.


Asd, odważni.

/goznacza „globalny”, co oznacza, że ​​należy to robić dla całej linii. Jeśli opuścisz /g(z s/few/asd/, zawsze muszą być trzy ukośniki bez względu na wszystko) i fewpojawi się dwa razy w tym samym wierszu, tylko pierwszy fewzostanie zmieniony na asd:

Kilku mężczyzn, kilka kobiet, odważnych.


Asd mężczyźni, nieliczne kobiety, odważni.

Jest to przydatne w niektórych okolicznościach, takich jak zmiana znaków specjalnych na początku wierszy (na przykład zastąpienie symboli większości używanych przez niektórych ludzi do cytowania poprzedniego materiału w wątkach e-maili za pomocą poziomej tabulatora, pozostawiając cytowaną nierówność algebraiczną w dalszej części wiersza nietknięty), ale w Twoim przykładzie, w którym określasz, że gdziekolwiek few występuje, należy go wymienić, upewnij się, że masz to /g.

Następujące dwie opcje (flagi) są połączone w jedną -ie:

-iOpcja ta służy do edycji I n miejsce na plik hello.txt.

-eOpcja wskazuje e Xpression / polecenie Uruchom, w tym przypadku s/.

Uwaga: ważne jest, -i -eaby wyszukiwać / zamieniać. Jeśli to zrobisz -ie, utworzysz kopię zapasową każdego pliku z dołączoną literą „e”.

Chaminda Bandara
źródło
0

Prostszą alternatywą jest użycie AWK w tej odpowiedzi :

awk '$0="prefix"$0' file > new_file

znak
źródło