Wyszukiwanie podciągów bez rozróżniania wielkości liter w skrypcie powłoki [zamknięte]


22

Jak napisać skrypt powłoki, który dopasuje podciągi znaków bez rozróżniania wielkości liter do danych wyjściowych polecenia?


grep -imoże?
Ramesh

Jak mam to umieścić w skrypcie? Przepraszam, jeśli to pytania początkujące. Właśnie zaczynam studiować Linuksa, ponieważ potrzebuję go na staż. Dzięki!
Miguel Roque

1
Pytasz o skrypty powłoki - „linux” nie jest językiem programowania, to jądro systemu operacyjnego. Powłoka najczęściej używana w Linuksie jest bashnadzbiorem standardu unixsh . Możesz zacząć od jednego z następujących: | 1 | | 2 | - tylko po to, aby poznać rzeczywisty kontekst.
goldilocks

1
To pytanie wydaje się teraz dość jasne i odpowiada wytycznym w centrum pomocy. Czy można go otworzyć z korzyścią dla innych?
BobDoolittle

2
Nie widzę problemu, dlaczego to pytanie nie jest jasne. Co powinienem dodać, żeby było jasne?
Miguel Roque

Odpowiedzi:


11

Najpierw jest prosty przykładowy skrypt, który nie ignoruje wielkości liter:

#!/bin/bash
if [ $(echo hello) == hello ]; then
    echo it works
fi

Spróbuj zmienić łańcuch „witaj” po prawej stronie i nie powinien on już odbijać echa it works. Spróbuj zastąpić wybraną echo hellokomendą. Jeśli chcesz zignorować wielkość liter, a żaden ciąg nie zawiera podziału wiersza, możesz użyć grep:

#!/bin/bash
if echo Hello | grep -iqF hello; then
    echo it works
fi

Kluczem tutaj jest to, że przekazujesz dane wyjściowe polecenia grep. ifOświadczenie testuje kod zakończenia pierwszej z prawej strony komendy w rurociągu - w tym przypadku grep. Grep kończy się sukcesem tylko wtedy, gdy znajdzie dopasowanie.

-iOpcja grep mówi zignorować sprawę. Opcja mówi się nie emitować wyjście i wyjście po pierwszym meczu. Opcja mówi traktować jako argument ciąg zamiast wyrażenia regularnego.
-q
-F

Zauważ, że w pierwszym przykładzie zastosowano bezpośrednie porównania i różne przydatne operatory. Drugi formularz po prostu wykonuje polecenia i testuje ich status wyjścia.[ expression ]


Nie rozumiem, dlaczego Gilles uznał za konieczne zmienić kod, który napisałem. Nic nie złamał, ale działało dobrze. W tym przykładzie nie potrzebujesz podwójnych cudzysłowów - są one ważne, jeśli dane wyjściowe zawierają spacje. A == działa tak samo dobrze jak =, ponieważ sh to w rzeczywistości Linux. Oryginalna powłoka Bourne'a już dawno zniknęła. Nie sądzę, żeby nawet Solaris już to wysyłał. Chociaż w tym przykładzie nie jest to konieczne, zgadzam się, że podwójne cudzysłowy są prawdopodobnie najlepszą praktyką, ale moim zdaniem również „==”, aby wyraźnie oddzielić przypisanie i porównanie.
BobDoolittle

Zaczekaj, więc można edytować post? Nie wiedziałem tego.
Miguel Roque

Przy wystarczającej reputacji tak. Mam jednak nadzieję, że ktoś o wysokiej reputacji pomyśli dwa razy, zanim wprowadzi niepotrzebne zmiany, szczególnie w celu kodowania na tym forum. unix.stackexchange.com/help/privileges
BobDoolittle

@ BobDoolittle W niektórych przypadkach może to mieć znaczenie, ale nie w konfiguracji - dobrze wiedzieć.

2
Pamiętaj, że w praktyce nie chodzi tylko o powłokę Bourne'a. ==nie jest POSIX. shnie jest dostępny bashwe wszystkich systemach Linux. ==nie jest obsługiwany przez ash(na którym shopiera się przynajmniej wiele BSD i pochodnych Debiana) lub posh, i wymaga cytowania w zsh. Nie ma sensu podwoić =. [to polecenie do testowania. Tutaj nie trzeba rozróżniać między przypisaniem a porównaniem. To różni się w (( a == b ))porównaniu do (( a = b)). Używanie ==w skrypcie, który zaczyna się od, #! /bin/shjest nieprawidłowe. Jeśli przyjmujesz kshlub bashskładnia, zaktualizuj #!odpowiednio.
Stéphane Chazelas

49

Możesz ustawić rozróżnianie wielkości liter bez rozróżniania wielkości liter bashprzy użyciu operatora regex, =~jeśli ustawisz nocasematchopcję powłoki. Na przykład

s1="hElLo WoRlD"
s2="LO"

shopt -s nocasematch

[[ $s1 =~ $s2 ]] && echo "match" || echo "no match"
match

s1="gOoDbYe WoRlD"
[[ $s1 =~ $s2 ]] && echo "match" || echo "no match"
no match

6
lol! punkty za niejasną wiedzę na temat powłoki.
BobDoolittle

2
Ta opcja wpływa również na prosty operator dopasowania. [[ XYZ == xyz ]] && echo "match"=>match
itsadok

7

Aby wyszukać ciąg znaków z uwzględnieniem wielkości liter, wartość zmiennej needlew wartości zmiennej haystack:

case "$haystack" in
  *"$needle"*) echo "present";
  *) echo "absent";
esac

Aby wyszukać ciąg znaków bez rozróżniania wielkości liter, przekonwertuj oba na tę samą wielkość liter.

uc_needle=$(printf %s "$needle" | tr '[:lower:]' '[:upper:]' ; echo .); uc_needle=${uc_needle%.}
uc_haystack=$(printf %s "$haystack" | tr '[:lower:]' '[:upper:]' ; echo .); uc_haystack=${uc_haystack%.}
case "$uc_haystack" in
  *"$uc_needle"*) echo "present";;
  *) echo "absent";;
esac

Zauważ, że trcoreutils w GNU nie obsługują wielobajtowych ustawień regionalnych (np. UTF-8). Aby pracować z ustawieniami wielobajtowymi, użyj zamiast tego awk. Jeśli zamierzasz użyć awk, możesz sprawić, że porówna ciąg znaków, a nie tylko konwersję.

if awk 'BEGIN {exit !index(toupper(ARGV[2]), toupper(ARGV[1]))}' "$needle" "$haystack"; then
  echo "present"
else
  echo "absent"
fi

Funkcja trBusyBox nie obsługuje składni; możesz zamiast tego użyć . BusyBox nie obsługuje ustawień regionalnych innych niż ASCII.[:CLASS:]tr a-z A-Z

W wersji bash (ale nie sh) w wersji 4.0+ istnieje wbudowana składnia do konwersji wielkości liter i prostsza składnia do dopasowywania ciągów.

if [[ "${haystack^^}" = *"${needle^^}"* ]]; then
  echo "present"
else
  echo "absent"
esac

Zdaję sobie sprawę, że to kilka lat, ale to wszystko printf | trsprawia, że kręci mi się w głowie. Tam, gdzie to możliwe, ograniczaj wywoływanie poleceń do minimum ... biorąc pod uwagę zmienną v, możesz zrobić to samo za pomocą v=$(tr '[:lower:]' '[:upper:]' <<<$v). Dla tych, którzy nigdy go nie widzieli, <<<jest to w zasadzie „zmienna tutaj”, tak jak w <<EOFprzypadku dokumentu tutaj. Nie printfbądź echochyba że koniecznie musisz to zrobić.
Czy

@Will To działa tylko w powłokach, które mają <<<operator: ksh, bash, zsh, ale nie zwykły sh. I jest bardzo zbliżony do potokowania printfpod względem sposobu działania: istnieje taka sama liczba wywołań do forki execve(zakładając, że printfjest wbudowany, co ma miejsce w większości popularnych powłok); Różnica polega na tym, że <<<tworzy plik tymczasowy zamiast używania potoku. <<<wygodnie jest pisać, ale nie poprawia wydajności.
Gilles „SO- przestań być zły”
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.