Lepszy sposób na wykonanie „echo $ x | sed… ”i„ echo $ x | grep… ”

14

Często znajduję to w skryptach (i muszę przyznać, że sam to piszę):

a=$(echo "$x" | sed "s/foo/bar/")

lub

if echo "$x" | grep -q foo
then
    ...
fi

Rozważ „foo”, aby uwzględnić niektóre wyrażenia regularne.

Czuję, że nie powinno być - i najczęściej jest - lepszy sposób na wyrażenie tego, jeden, który nie wiąże się z dwóch poleceń i fajki ale owija rzeczy do jakiegoś bardziej zwartej wypowiedzi.

Po prostu nie mogę tego znaleźć. Ktoś?

DevSolar
źródło
spodziewam się, że to wyrażenie jest często używane ze względu na kombinację ignorancji (nie znanie alternatyw) i łatwości konserwacji (znajomość alternatyw, ale wybranie tego jako prostszego do zrozumienia). mogę na pierwszy rzut oka powiedzieć, co robią twoje przykłady, ale potrzebuję odwołania do powłoki, aby znaleźć alternatywne rozwiązania w odpowiedziach grawitacji i Dana McG.
quack quixote
3
Nawiasem mówiąc, preferowaną metodą zastępowania poleceń jest $()raczej odwrotność.
Wstrzymano do odwołania.
2
Dobrym pomysłem jest również cytowanie rozszerzeń, aby chronić białe spacje: a="$(echo "$x" | sed "s/foo/bar/")"i if echo "$x" | grep foo; ….
Chris Johnsen,
Dobre uwagi na temat $ () vs. ``. Widzę, że moje umiejętności bashowe nie są jeszcze tak świetne.
DevSolar

Odpowiedzi:

12

O ile nie założysz konkretnej powłoki, nie ma lepszego sposobu na zrobienie tego niż „echo potoku do narzędzia” (lub samo „narzędzie”, takie jak wyrażenie ); to wszystko, na co możesz naprawdę liczyć dzięki tradycyjnej powłoce Bourne'a i / lub powłoce POSIX . Jeśli weźmiesz pod uwagę inne powłoki, istnieje kilka innych wbudowanych możliwości.

ksh ma

  • dodatkowe wzory: ?(pattern-list), *(pattern-list), {n}(pattern-list), {n,m}(pattern-list), @(pattern-list), !(pattern-list);
  • specyfikator %P printf do konwersji rozszerzonego wyrażenia regularnego na wzorzec (i %Rrozszerzonego wyrażenia regularnego na wzorzec);
  • expr == patternstan, w [[ expr ]]badaniach;
  • ${param/pattern/replacement}rozszerzenie parametrów.

bash ma

  • extglobopcja w celu umożliwienia większość dodatkowych wzorców ksh (no {n}i {n,m});
  • expr == patternwarunek (w [[ expr ]]badaniach);
  • ${param/pattern/replacement}rozszerzenie parametrem;
  • (w nowszych wersjach) expr =~ extregexpwarunek (w [[ expr ]]testach), który może pasować do rozszerzonych wyrażeń regularnych
    • z podwyrażeniami w nawiasach i BASH_REMATCHparametrem można było zastąpić styl sed .

zsh ma

  • własne rozszerzone wzory z EXTENDED_GLOBopcją;
  • wzorce rozszerzone przypominające ksh z KSH_GLOBopcją;
  • expr == patternwarunek (w [[ expr ]]badaniach);
  • ${pattern/pattern/replacement}rozszerzenie parametrem;
  • expr =~ extregexpwarunek (w [[ expr ]]testach), które można dopasować przeciwko rozszerzonych wyrażeń regularnych,
    • może używać PCRE zamiast zwykłych rozszerzonych wyrażeń regularnych, jeśli ustawiona jest opcja RE_MATCH_PCRE,
    • z podwyrażeniami w nawiasach, MATCHparametrem i matchparametrem (lub BASH_REMATCHz BASH_REMATCHzestawem opcji) można było zastąpić styl sed ;
  • zsh/pcremoduł oferty pcre_compile, pcre_study, i pcre_matchpoleceń oraz -pcre-match testu (przydatność w [[ expr ]]testach);
  • zsh/regexmoduł, który oferuje -regex-match testową warunek (w [[ expr ]]testach).
Chris Johnsen
źródło
Łał. Tak kompletne, jak tylko można sobie życzyć. Zdecydowanie zwycięzca.
DevSolar
6

Aby zastąpić linię sed, zrób coś takiego

${a/foo/bar} lub ${a//foo/bar}

W pierwszej formie zastępowana jest tylko pierwsza instancja. Druga forma to globalne wyszukiwanie i zamiana.

W twoim przypadku byłoby

Zamiast:

if echo $x | grep foo
then
    ...
fi

Rozważ użycie:

if [ $x =~ foo ]
then
    ...
fi

Gdzie foojest wyrażenie regularne.

Dan McGrath
źródło
W jakich powłokach to działa?
Peltier
1
if [ $x =~ foo ]wyświetla tutaj komunikat o błędzie. if [[ $x =~ foo ]]działa jednak świetnie. Dzięki!
DevSolar
1
Wszystko to są bashizmy, wymagają bashu. Ponadto =~wymaga uderzenia> = 3 iirc.
ℝaphink
1
Iirc również, foo nie jest wyrażeniem regularnym (jak w PCRE) w tych przykładach, ale używa symboli wieloznacznych. Więcej na temat dobroci basha znajduje się na stronie podręcznika bash, sekcja „Rozszerzanie parametrów”. Szczególnie doceniam takie rzeczy jak ${a##foo}i ${a%%bar}.
ℝaphink
3
Operator dopasowania =~używa wyrażeń regularnych. Dotyczy to na przykład: [[ "abcdddde" =~ ^a.*d+.g* ]](to na przykład zero lub więcej g zamiast symboli wieloznacznych g).
Wstrzymano do odwołania.
2

Dobrym sposobem na sprawdzenie, czy zmienna zawiera wzorzec, zgodny z posixem jest:

test ${var##*foo*} || <do something>;

Składnia rozszerzenia parametru jest następująca:

 ${parameter##pattern}

gdzie patternjest wzór powłoki .

mrucci
źródło