Mam „I love Suzi and Marry” i chcę zmienić „Suzi” na „Sara”.
#!/bin/bash
firstString="I love Suzi and Marry"
secondString="Sara"
# do something...
Wynik musi być taki:
firstString="I love Sara and Marry"
Mam „I love Suzi and Marry” i chcę zmienić „Suzi” na „Sara”.
#!/bin/bash
firstString="I love Suzi and Marry"
secondString="Sara"
# do something...
Wynik musi być taki:
firstString="I love Sara and Marry"
Odpowiedzi:
Aby zastąpić pierwsze wystąpienie wzorca danym ciągiem, użyj :${parameter/pattern/string}
#!/bin/bash
firstString="I love Suzi and Marry"
secondString="Sara"
echo "${firstString/Suzi/$secondString}"
# prints 'I love Sara and Marry'
Aby zastąpić wszystkie wystąpienia, użyj :${parameter//pattern/string}
message='The secret code is 12345'
echo "${message//[0-9]/X}"
# prints 'The secret code is XXXXX'
(Jest to opisane w podręczniku atakujących odniesienia , §3.5.3 „Shell parametrów Expansion” ).
Zauważ, że ta funkcja nie jest określona przez POSIX - jest to rozszerzenie Bash - więc nie wszystkie powłoki Unix ją implementują. Aby zapoznać się z odpowiednią dokumentacją POSIX, zobacz Podstawową specyfikację standardu technicznego Open Group, wydanie 7 , tom Shell & Utilities , § 2.6.6 „Rozszerzanie parametrów” .
\n
w tym kontekście reprezentowałby siebie, a nie nowy wiersz. Nie mam Bash poręczny prawo teraz do testu, ale powinieneś być w stanie napisać coś podobnego $STRING="${STRING/$'\n'/<br />}"
. (Chociaż prawdopodobnie chcesz STRING//
- zamień wszystko - zamiast tylko STRING/
.)
echo ${my string foo/foo/bar}
. Potrzebujeszinput="my string foo"; echo ${input/foo/bar}
//
bezpośrednio wspomnieć , wspomina, co się dzieje „Jeśli wzorzec zaczyna się od /
„ ”(co nie jest nawet dokładne, ponieważ reszta tego zdania zakłada, że dodatkowe /
nie jest tak naprawdę częścią wzór) - ale nie znam lepszego źródła.
Można to zrobić całkowicie za pomocą manipulacji ciągiem bash:
first="I love Suzy and Mary"
second="Sara"
first=${first/Suzy/$second}
To zastąpi tylko pierwsze wystąpienie; aby zamienić je wszystkie, podwój pierwszy ukośnik:
first="Suzy, Suzy, Suzy"
second="Sara"
first=${first//Suzy/$second}
# first is now "Sara, Sara, Sara"
W przypadku Dasha wszystkie poprzednie posty nie działają
Rozwiązaniem sh
zgodnym z POSIX jest:
result=$(echo "$firstString" | sed "s/Suzi/$secondString/")
result=$(echo $firstString | sed "s/Suzi/$secondString/g")
echo
argumentu. Zwodniczo działa bez cytowania przy użyciu prostych ciągów, ale łatwo psuje dowolny nietrywialny ciąg wejściowy (nieregularne odstępy, metaznaki powłoki itp.).
Spróbuj tego:
sed "s/Suzi/$secondString/g" <<<"$firstString"
Lepiej jest używać bash, niż sed
jeśli łańcuchy zawierają znaki RegExp.
echo ${first_string/Suzi/$second_string}
Jest przenośny dla systemu Windows i działa z co najmniej tak starym jak Bash 3.1.
Aby pokazać, że nie musisz się zbytnio przejmować ucieczką, obróćmy to:
/home/name/foo/bar
Zaangażowany w to:
~/foo/bar
Ale tylko jeśli /home/name
jest na początku. Nie potrzebujemy sed
!
Biorąc pod uwagę, że bash daje nam magiczne zmienne $PWD
i $HOME
możemy:
echo "${PWD/#$HOME/\~}"
EDYCJA: Dzięki za Mark Haferkamp w komentarzach do notatki na temat cytowania / ucieczki ~
. *
Zauważ, że zmienna $HOME
zawiera ukośniki, ale to niczego nie zepsuło.
Dalsza lektura: Przewodnik po zaawansowanych skryptach bashowych .
Jeśli używanie sed
jest koniecznością, pamiętaj o ucieczce każdej postaci .
sed
z pwd
poleceniem, aby uniknąć definiowania nowej zmiennej za każdym razem moje własne $PS1
przejazdy. Czy Bash zapewnia bardziej ogólny sposób niż zmienne magiczne wykorzystanie wyjścia polecenia do zamiany łańcucha? Jeśli chodzi o twój kod, musiałem uciec, ~
aby Bash nie rozwinął go do $ HOME. Co również robi #
twoje polecenie?
~
”: zauważ, jak cytowałem różne rzeczy. Pamiętaj, aby zawsze cytować różne rzeczy! I to nie działa tylko w przypadku zmiennych magicznych: każda zmienna jest zdolna do podstawiania, uzyskiwania długości łańcucha i więcej w ramach bash. Gratulujemy $PS1
postu: możesz być także zainteresowany, $PROMPT_COMMAND
jeśli czujesz się lepiej w innym języku programowania i chcesz zakodować skompilowane zapytanie.
echo "${PWD/#$HOME/~}"
nie zastąpią mi $HOME
się ~
. Wymiana ~
z \~
lub '~'
prace. Każda z nich działa na Bash 4.2.53 w innej dystrybucji. Czy możesz zaktualizować swój post, aby zacytować lub uciec przed ~
lepszą kompatybilnością? Moje pytanie „magiczne zmienne” miałem na myśli: czy mogę użyć podstawienia zmiennej Basha, np. Na wyjściu uname
bez zapisywania go jako zmiennej? Jeśli chodzi o mój osobisty $PROMPT_COMMAND
, to skomplikowane .
Jeśli jutro zdecydujesz, że nie kochasz Marry, ona również może zostać zastąpiona:
today=$(</tmp/lovers.txt)
tomorrow="${today//Suzi/Sara}"
echo "${tomorrow//Marry/Jesica}" > /tmp/lovers.txt
Musi być 50 sposobów na opuszczenie kochanka.
Ponieważ nie mogę dodać komentarza. @ruaka Aby uczynić przykład bardziej czytelnym, napisz go w ten sposób
full_string="I love Suzy and Mary"
search_string="Suzy"
replace_string="Sara"
my_string=${full_string/$search_string/$replace_string}
or
my_string=${full_string/Suzy/Sarah}
Czysta POSIX metoda powłoki, które w odróżnieniu od Roman Kazanovskyi „s sed
opartym odpowiedź potrzebuje żadnych zewnętrznych narzędzi, zaledwie ojczystym skorupy za ekspansje parametrów . Zauważ, że długie nazwy plików są zminimalizowane, więc kod lepiej pasuje do jednej linii:
f="I love Suzi and Marry"
s=Sara
t=Suzi
[ "${f%$t*}" != "$f" ] && f="${f%$t*}$s${f#*$t}"
echo "$f"
Wynik:
I love Sara and Marry
Jak to działa:
Usuń najmniejszy wzór sufiksu. "${f%$t*}"
zwraca „ I love
”, jeśli sufiks $t
„ Suzi*
” jest w $f
„ ”. I love
Suzi and Marry
Ale jeśli t=Zelda
, to "${f%$t*}"
nic nie usuwa i zwraca cały ciąg „ I love Suzi and Marry
”.
Służy do testowania, czy $t
jest w, $f
z [ "${f%$t*}" != "$f" ]
którym ma wartość true, jeśli $f
ciąg zawiera „ Suzi*
”, a fałsz, jeśli nie.
Jeśli test zwróci wartość true , skonstruuj żądany ciąg znaków, używając opcji Usuń najmniejszy wzorzec sufiksu ${f%$t*}
„ I love
” i Usuń najmniejszy wzorzec prefiksu ${f#*$t}
„ and Marry
”, z drugim ciągiem $s
„ Sara
” pomiędzy nimi.
Wiem, że to stare, ale ponieważ nikt nie wspomniał o używaniu awk:
firstString="I love Suzi and Marry"
echo $firstString | awk '{gsub("Suzi","Sara"); print}'
echo [string] | sed "s/[original]/[target]/g"