2013-05-18 22 views
258

W moim skrypcie bash mam ciąg znaków i jego prefiks/sufiks. Potrzebuję usunąć przedrostek/przyrostek z oryginalnego łańcucha.Usuń stały prefiks/przyrostek z ciągu znaków w Bash

Na przykład, powiedzmy, że mam następujące wartości:

string="hello-world" 
prefix="hell" 
suffix="ld" 

Jak mogę dostać się do następnego wyniku?

result="o-wor" 
+4

Spójrz [Advanced Bash-Scripting Guide] (http://tldp.org/LDP/abs/html/string-manipulation.html) – tarrsalah

+4

Bądź bardzo ostrożny podczas łączenia z tak zwanym Advanced Bash Scripting Guide; zawiera mieszaninę dobrych rad i okropnych. – tripleee

Odpowiedz

365
$ foo=${string#$prefix} 
$ foo=${foo%$suffix} 
$ echo "${foo}" 
o-wor 
+26

Istnieją również ## i %%, które usuwają tyle, ile to możliwe, jeśli $ prefix lub $ suffix zawierają symbole wieloznaczne. – pts

+12

Czy istnieje sposób na połączenie dwóch w jedną linię? Próbowałem '$ {$ {string # prefix}% suffix}', ale to nie działa. –

+15

@static_rtti Nie, niestety nie można zagnieździć podstawiania parametrów w ten sposób. Wiem, szkoda. –

49

Korzystanie sed:

$ echo "$string" | sed -e "s/^$prefix//" -e "s/$suffix$//" 
o-wor 

ciągu polecenia sed, postać ^ pasuje tekst począwszy $prefix i spływu tekst $ mecze kończąc $suffix.

Adrian Frühwirth ma kilka dobrych punktów w komentarzach poniżej, ale w tym celu może być bardzo przydatny sed. Fakt, że zawartość prefiksu $ i sufiksu $ jest interpretowana przez sed może być dobra lub zła - tak długo, jak zwracasz uwagę, powinieneś być w porządku. Piękno jest, można zrobić coś takiego:

$ prefix='^.*ll' 
$ suffix='ld$' 
$ echo "$string" | sed -e "s/^$prefix//" -e "s/$suffix$//" 
o-wor 

która może być to, co chcesz, i to zarówno hodowcy i mocniejsze niż bash zmiennej zastąpienia. Jeśli pamiętasz, że z wielką siłą wiąże się wielka odpowiedzialność (jak mówi Spiderman), powinieneś być w porządku.

Szybkie wprowadzenie do sed można znaleźć na http://evc-cit.info/cit052/sed_tutorial.html

notatkę dotyczącą powłoki i jej stosowanie łańcuchów:

Dla konkretnego przykładu podanego następujący będzie pracować także:

$ echo $string | sed -e s/^$prefix// -e s/$suffix$// 

... ale tylko dlatego, że:

  1. echo nie obchodzi mnie, jak wiele ciągi są w liście argumentów, a
  2. Brak miejsca w $ prefix i $ przyrostkiem

To ogólnie dobra praktyka, aby zacytować ciąg w wierszu polecenia, ponieważ nawet jeśli zawiera spacje zostanie przedstawione do polecenia jako pojedynczy argument. Cytujemy $ prefix i $ sufiks z tego samego powodu: każde polecenie edycji sed zostanie przekazane jako jeden ciąg znaków. Używamy podwójnych cudzysłowów, ponieważ pozwalają one na zmienną interpolację; Gdybyśmy użyli pojedynczych cudzysłowów, komenda sed dostałaby dosłowne $prefix i $suffix, co z pewnością nie jest tym, czego chcieliśmy.

Zauważcie też, że używam pojedynczych cudzysłowów przy ustawianiu zmiennych prefix i suffix. Z pewnością nie chcemy, aby cokolwiek w smyczkach było interpretowane, więc pojedynczo je cytujemy, więc nie ma miejsca interpolacja. Ponownie, może nie być to konieczne w tym przykładzie, ale jest to bardzo dobry nawyk.

+5

Niestety , jest to zła rada z kilku powodów: 1) Unquoted, '$ string' jest przedmiotem dzielenia słów i globowania. 2) '$ prefix' i' $ suffix' mogą zawierać wyrażenia, które 'sed' będą interpretować, np. wyrażeń regularnych lub znaku używanego jako ogranicznik, który przerwie całe polecenie. 3) Wywołanie "sed" dwa razy nie jest konieczne (zamiast tego można użyć '-e 's ///' -e '///''), a rura może również zostać pominięta. Rozważmy na przykład 'string = './*'' I/lub 'prefix = '. /'' I zobaczmy, jak strasznie się łamie z powodu '1)' i '2)'. –

+0

Uwaga dla zabawy: sed może potrwać niemal wszystko jako ogranicznik. W moim przypadku, ponieważ analizowałem prefiksy-katalogi ze ścieżek, nie mogłem użyć '/', więc użyłem 'sed '# # $ $ prefix ##' (zamiast tego: Fraguel: nazwy plików nie mogą zawierać '/' # '. Ponieważ kontroluję pliki, jesteśmy bezpieczni.) – Olie

+0

@Olie Nazwy plików mogą zawierać * dowolny * znak oprócz znaku ukośnika i znaku pustego, więc dopóki nie masz kontroli, nie możesz przyjąć nazwy pliku, aby nie zawierała określonych znaków. –

11

używam grep do usuwania prefiksów ze ścieżek (które nie są obsługiwane przez dobrze sed):

echo "$input" | grep -oP "^$prefix\K.*" 

\K usuwa z meczu wszystkie znaki przed nim.

10

Czy znasz długość prefiksu i sufiksu? W twoim przypadku:

result=$(echo $string | cut -c5- | rev | cut -c3- | rev) 

Albo bardziej ogólnym:

result=$(echo $string | cut -c$((${#prefix}+1))- | rev | cut -c$((${#suffix}+1))- | rev) 

Ale solution from Adrian Frühwirth jest sposób fajne! Nie wiedziałem o tym!

1

Korzystanie @Adrian Frühwirth odpowiedź:

function strip { 
    local STRING=${1#$"$2"} 
    echo ${STRING%$"$2"} 
} 

używać go tak jak to

HELLO=":hello:" 
HELLO=$(strip "$HELLO" ":") 
echo $HELLO # hello 
4

Małych i uniwersalnego rozwiązania:

expr "$string" : "$prefix\(.*\)$suffix" 
1

Korzystanie z =~ operator:

$ string="hello-world" 
$ prefix="hell" 
$ suffix="ld" 
$ [[ $string =~ $prefix(.*)$suffix ]] && echo "${BASH_REMATCH[1]}" 
o-wor 
Powiązane problemy