Mam ciąg w Bash:
string="My string"
Jak mogę sprawdzić, czy zawiera inny ciąg?
if [ $string ?? 'foo' ]; then
echo "It's there!"
fi
Gdzie ??
jest mój nieznany operator. Czy używam echa i grep
?
if echo "$string" | grep 'foo'; then
echo "It's there!"
fi
To wygląda trochę niezdarnie.
expr
polecenia tutajOdpowiedzi:
Możesz użyć odpowiedzi Marcusa (* symboli wieloznacznych) poza instrukcją case, jeśli używasz podwójnych nawiasów:
Zauważ, że spacje w ciągu igły muszą być umieszczone między podwójnymi cudzysłowami, a
*
symbole wieloznaczne powinny znajdować się na zewnątrz. Zauważ też, że używany jest prosty operator porównania (tj.==
), A nie operator wyrażenia regularnego=~
.źródło
#!/bin/sh
. Spróbuj#!/bin/bash
zamiast tego.[[
. Zobacz ideone.com/ZSy1gZJeśli wolisz podejście wyrażenia regularnego:
źródło
=~
Operator już przeszukuje cały ciąg na mecz; te.*
„s są tu obcy. Również cytaty są na ogół lepsze niż ukośniki odwrotne:[[ $string =~ "My s" ]]
E14)
. Prawdopodobnie najlepiej przypisać do zmiennej (używając cudzysłowów), a następnie porównać. W ten sposób:re="My s"; if [[ $string =~ $re ]]
if [[ ! "abc" =~ "d" ]]
prawda.number=2; if [[ "1, 2, 4, 5" = *${number}* ]]; then echo forward $number; fi; if [[ *${number}* = "1, 2, 4, 5" ]]; then echo backwards $number; fi;
Nie jestem pewien co do użycia instrukcji if, ale możesz uzyskać podobny efekt dzięki instrukcji case:
źródło
[[ $string == *foo* ]]
działa również w niektórych wersjach sh zgodnych z POSIX (np./usr/xpg4/bin/sh
w Solarisie 10) i ksh (> = 88)[[
... przełącznik skrzynek działał!stringContain
warianty (kompatybilne lub niezależne od wielkości liter)Ponieważ te odpowiedzi dotyczące przepełnienia stosu mówią głównie o Bash , na samym dole tego postu opublikowałem niezależną od wielkości funkcję Bash ...
W każdym razie jest mój
Kompatybilna odpowiedź
Ponieważ jest już wiele odpowiedzi za pomocą funkcji specyficznych dla Bash, istnieje sposób działania w słabszych powłokach, takich jak BusyBox :
W praktyce może to dać:
Zostało to przetestowane pod Bash, Dash , KornShell (
ksh
) i ash (BusyBox), a wynik jest zawsze:W jedną funkcję
Jak pyta @EeroAaltonen tutaj jest wersja tego samego demo, przetestowana pod tymi samymi powłokami:
Następnie:
Uwaga: musisz uciec lub podwójnie dołączyć cudzysłowy i / lub podwójne cudzysłowy:
Prosta funkcja
Zostało to przetestowane pod BusyBox, Dash i oczywiście Bash:
Więc teraz:
... Lub jeśli przesłany ciąg może być pusty, jak wskazał @Sjlver, funkcja wyglądałaby następująco:
lub jak sugeruje komentarz Adriana Güntera , unikając
-o
przełączników:Ostateczna (prosta) funkcja:
I odwracanie testów, aby były potencjalnie szybsze:
Z pustymi łańcuchami:
Niezależny od wielkości liter (tylko Bash!)
Aby przetestować ciągi bez dbania o wielkość liter, po prostu przekonwertuj każdy ciąg na małe litery:
Czek:
źródło
string_contains() { [ -z "${2##*$1*}" ] && [ -n "$2" -o -z "$1" ]; }
Ostatnia myśl: czy pusty ciąg zawiera pusty ciąg? Wersja powyżej rzeczy tak (z powodu tej-o -z "$1"
części).Powinieneś pamiętać, że skrypty powłoki to mniej język, a raczej zbiór poleceń. Instynktownie myślisz, że ten „język” wymaga, abyś podążał za
if
znakiem „a”[
lub „a”[[
. Oba są tylko poleceniami, które zwracają status wyjścia wskazujący powodzenie lub niepowodzenie (tak jak każde inne polecenie). Z tego powodu użyjęgrep
, a nie[
polecenia.Po prostu zrób:
Teraz, gdy myślisz o
if
testowaniu statusu wyjścia polecenia, które następuje po nim (wraz z dwukropkiem), dlaczego nie ponownie rozważyć źródła testowanego ciągu?Ta
-q
opcja powoduje, że grep nic nie wypisuje, ponieważ chcemy tylko kodu powrotu.<<<
sprawia, że powłoka rozszerza następne słowo i używa go jako danych wejściowych do polecenia, wersji jednego wiersza<<
dokumentu tutaj (nie jestem pewien, czy jest to standard czy baszizm).źródło
if grep -q foo <(echo somefoothing); then
echo
można tego przenieść, jeśli przekazujesz zmienną, użyjprintf '%s' "$string
zamiast tego.grep -q foo <<<"$mystring"
widelca implikuje 1 i jest bashizmem iecho $mystring | grep -q foo
implikuje 2 widelce (jeden do fajki, a drugi do biegania/path/to/grep
)echo
bez flag może nadal mieć nieoczekiwane problemy z przenośnością, jeśli ciąg argumentu zawiera sekwencje odwrotnego ukośnika.echo "nope\c"
oczekuje się, że na niektórych platformach będzie działać tak, jakecho -e "nope"
na innych.printf '%s' "nope"
vsprintf '%s\n' 'nope\c'
Najlepsza jest zaakceptowana odpowiedź, ale ponieważ jest na to więcej niż jeden sposób, oto inne rozwiązanie:
${var/search/replace}
jest$var
z pierwszą instancjąsearch
zastąpioną przezreplace
, jeśli zostanie znaleziona (nie zmienia się$var
). Jeśli spróbujesz zastąpićfoo
nic, a łańcuch się zmienił, to oczywiściefoo
znaleziono.źródło
Istnieje więc wiele przydatnych rozwiązań tego pytania - ale które jest najszybsze / zużywa najmniej zasobów?
Powtórzone testy przy użyciu tej ramki:
Wymiana TESTU za każdym razem:
(doContain był w odpowiedzi F. Houri)
A dla chichotów:
Zatem prosta opcja podstawienia jest przewidywalnie wygrana, czy to w rozszerzonym teście, czy w przypadku. Obudowa jest przenośna.
Wypompowanie do 100000 greps jest przewidywalnie bolesne! Stara zasada korzystania z zewnętrznych narzędzi bez potrzeby ma zastosowanie.
źródło
[[ $b == *$a* ]]
.case
wygrywa przy najmniejszym całkowitym zużyciu czasu. Po tym jednak brakuje Ci gwiazdki$b in *$a
. Otrzymuję nieco szybsze wyniki[[ $b == *$a* ]]
niżcase
z poprawionym błędem, ale oczywiście może to zależeć również od innych czynników.[[ $b == *$a* ]]
jest szybki icase
prawie tak szybki (i przyjemnie zgodny z POSIX).Działa to również:
A negatywny test to:
Podejrzewam, że ten styl jest nieco bardziej klasyczny - mniej zależny od cech powłoki Bash.
--
Argument jest czysta paranoja POSIX, używane do zabezpieczone przed ciągach podobnych do opcji, takich jak--abc
czy-a
.Uwaga: W ciasnej pętli kod ten będzie znacznie wolniejszy niż przy użyciu wewnętrznych funkcji powłoki Bash, ponieważ jeden (lub dwa) osobne procesy zostaną utworzone i połączone za pomocą potoków.
źródło
echo
jest nieprzenośny, powinieneś użyćprintf '%s' "$haystack
zamiast tego.echo
całkowicie niczego poza dosłownym tekstem bez znaków ucieczki, które nie zaczynają się od-
. Może to działać dla Ciebie, ale nie jest przenośne. Nawet bashecho
zachowa się inaczej w zależności od tego, czyxpg_echo
opcja jest ustawiona. PS: Zapomniałem zamknąć podwójny cytat w poprzednim komentarzu.--
nie jest wymieniony w specyfikacji POSIX dlaprintf
, ale i tak powinieneś użyćprintf '%s' "$anything"
, aby uniknąć problemów, jeśli$anything
zawiera%
znak.Przykłady Bash 4+. Uwaga: niestosowanie cudzysłowów spowoduje problemy, gdy słowa zawierają spacje itp. Zawsze cytuj w Bash, IMO.
Oto kilka przykładów Bash 4+:
Przykład 1, sprawdź ciąg „tak” (bez rozróżniania wielkości liter):
Przykład 2, sprawdź ciąg „tak” (bez rozróżniania wielkości liter):
Przykład 3, sprawdź ciąg „tak” (rozróżniana jest wielkość liter):
Przykład 4, sprawdź ciąg „tak” (rozróżniana jest wielkość liter):
Przykład 5, dopasowanie ścisłe (wielkość liter ma znaczenie):
Przykład 6, dopasowanie ścisłe (bez rozróżniania wielkości liter):
Przykład 7, dopasowanie ścisłe:
Przykład 8, dopasowanie do znaku wieloznacznego .ext (bez rozróżniania wielkości liter):
Cieszyć się.
źródło
Co powiesz na to:
źródło
Jak wspomniał Paweł w swoim porównaniu wyników:
Jest to zgodne z POSIX, takie jak „case” $ string ”w” odpowiedzi dostarczonej przez Marcusa , ale jest nieco łatwiejsze do odczytania niż odpowiedź instrukcji case. Zauważ też, że będzie to znacznie wolniejsze niż użycie instrukcji case. Jak zauważył Paul, nie używaj go w pętli.
źródło
Ta odpowiedź na przepełnienie stosu była jedyną, która uwięziła znaki spacji i myślników:
źródło
źródło
echo "Couldn't find
instrukcja na końcu jest fajną sztuczką, aby zwrócić 0 statusów wyjścia dla tych pasujących poleceń.|| echo "Couldn't find"
, zwrócisz status wyjścia z błędu, jeśli nie ma zgodności, czego możesz nie chcieć, jeśli korzystasz z potoku CI, na przykład, aby wszystkie komendy zwróciły bez błędów statusy wyjściaJeden jest:
źródło
expr
jest jednym z tych noży szwajcarskich, które zwykle potrafią zrobić wszystko, co trzeba, kiedy już wymyślisz, jak to zrobić, ale po wdrożeniu nigdy nie będziesz pamiętać, dlaczego i jak to robi, więc nigdy więcej go nie dotykaj i miej nadzieję, że nigdy nie przestanie robić tego, co robi.expr
, w rzadkich przypadkach, gdy przenośność uniemożliwia użycie bash (np. Niespójne zachowanie w starszych wersjach), tr (niespójne wszędzie) lub sed (czasami zbyt wolno). Ale z własnego doświadczenia, za każdym razem, gdy czytam ponownie teexpr
-ismy, muszę wrócić do strony podręcznika. Chciałbym więc skomentować, że każde użycieexpr
komentowane ...expr
itest
zostały zaimplementowane do ich wykonania. W dzisiejszych czasach są zwykle lepsze narzędzia, wiele z nich wbudowanych w każdą nowoczesną powłokę. Chybatest
wciąż tam jest, ale chyba nikogo nie brakujeexpr
.Lubię sed.
Edycja, logika:
Użyj sed, aby usunąć wystąpienie podłańcucha z łańcucha
Jeśli nowy ciąg różni się od starego, istnieje podciąg
źródło
grep -q
jest przydatny do tego celu.To samo przy użyciu
awk
:Wynik:
Wynik:
Oryginalne źródło: http://unstableme.blogspot.com/2008/06/bash-search-letter-in-string-awk.html
źródło
echo
jest nieprzenośny, powinieneś użyćprintf '%s' "$string"
zamiast tego. Edytuję odpowiedź, ponieważ wydaje się, że użytkownik już nie istnieje.echo
nie jest przenośny, @ nyuszika7h?Okazało się, że potrzebuję tej funkcji dość często, więc używam domowej powłoki w moim
.bashrc
podobnym, co pozwala mi używać go tak często, jak potrzebuję, z łatwą do zapamiętania nazwą:Aby sprawdzić, czy
$string1
(powiedzmy, abc ) jest zawarty w$string2
(powiedzmy, 123abcABC ), muszę po prostu uruchomićstringinstring "$string1" "$string2"
i sprawdzić wartość zwracaną, na przykładźródło
x
hack jest wymagany tylko w przypadku bardzo starych pocisków.Mój plik .bash_profile i sposób użycia grep:
Jeśli zmienna środowiskowa PATH zawiera moje dwa
bin
katalogi, nie dołączaj ich,źródło
grep -q -E 'pattern1|...|patternN'
.Rozszerzenie odpowiedzi na pytanie tutaj Jak sprawdzić, czy łańcuch zawiera inny ciąg w POSIX sh? :
To rozwiązanie działa ze znakami specjalnymi:
źródło
contains "-n" "n"
nie działa tutaj, ponieważecho -n
połknie-n
opcję jako opcję! Popularną poprawką jest użycieprintf "%s\n" "$string"
zamiast tego.Ponieważ pytanie POSIX / BusyBox jest zamknięte bez podania właściwej odpowiedzi (IMHO), opublikuję odpowiedź tutaj.
Najkrótsza możliwa odpowiedź to:
lub
Zauważ, że podwójny skrót jest obowiązkowy w przypadku niektórych powłok (
ash
). Powyżej oceni,[ stringvalue ]
kiedy nie zostanie znaleziony podciąg. Nie zwraca błędu. Po znalezieniu podłańcucha wynik jest pusty i ocenia[ ]
. Spowoduje to wyrzucenie kodu błędu 1, ponieważ ciąg jest całkowicie podstawiony (z powodu*
).Najkrótsza bardziej powszechna składnia:
lub
Inny:
lub
Zwróć uwagę na pojedynczy znak równości!
źródło
Dokładne dopasowanie słów:
źródło
Spróbuj oobash.
Jest to biblioteka ciągów w stylu OO dla Bash 4. Obsługuje niemieckie umlauty. Jest napisane w języku Bash.
Wiele funkcji dostępne są:
-base64Decode
,-base64Encode
,-capitalize
,-center
,-charAt
,-concat
,-contains
,-count
,-endsWith
,-equals
,-equalsIgnoreCase
,-reverse
,-hashCode
,-indexOf
,-isAlnum
,-isAlpha
,-isAscii
,-isDigit
,-isEmpty
,-isHexDigit
,-isLowerCase
,-isSpace
,-isPrintable
,-isUpperCase
,-isVisible
,-lastIndexOf
,-length
,-matches
,-replaceAll
,-replaceFirst
,-startsWith
,-substring
,-swapCase
,-toLowerCase
,-toString
,-toUpperCase
,-trim
, i-zfill
.Spójrz na zawiera przykład:
oobash jest dostępny na Sourceforge.net .
źródło
Używam tej funkcji (jedna zależność nie jest uwzględniona, ale oczywista). Przechodzi testy pokazane poniżej. Jeśli funkcja zwraca wartość> 0, łańcuch został znaleziony. Zamiast tego możesz równie łatwo zwrócić 1 lub 0.
źródło
To jest ta sama odpowiedź, co https://stackoverflow.com/a/229585/11267590 . Ale prosty styl, a także zgodny z POSIX.
źródło
Znajduje to każde wystąpienie a, b lub c
źródło
Ogólny przykład stogu siana z igłą podąża za zmiennymi
źródło