bash: test, zda je $ WORD v sadě

Hledám konstrukt v bash, abych se rozhodl, zda proměnná $WORD je jedno z definovaných slov. Potřebuji něco takového:

if "$WORD" in dog cat horse ; then echo yes else echo no fi 

má bash takový konstrukt? Pokud ne, jaké by bylo nejbližší?

Odpověď

Toto je řešení pouze pro Bash (> = verze 3), které používá regulární výrazy:

if [[ "$WORD" =~ ^(cat|dog|horse)$ ]]; then echo "$WORD is in the list" else echo "$WORD is not in the list" fi 

Pokud je váš seznam slov dlouhý, můžete jej uložit do souboru (jedno slovo na řádek) a provést toto:

if [[ "$WORD" =~ $(echo ^\($(paste -sd"|" /your/file)\)$) ]]; then echo "$WORD is in the list" else echo "$WORD is not in the list" fi 

Jedno upozornění s přístupem k souboru:

  • Rozbije se, pokud má soubor mezery. To lze napravit pomocí něčeho jako:

    sed "s/[[:blank:]]//g" /your/file | paste -sd "|" /dev/stdin 

Díky @terdon mi připomněl, abych správně ukotvil vzor pomocí ^ a $.

Komentáře

  • A shopt -s nocasematch může pomoci, pokud chcete, aby vyhledávání nerozlišovalo velká a malá písmena.
  • Upozorňujeme, že musíte použít [[ a ]][ a ] nestačí.
  • Hledal jsem pro ‚ oneliner ‚ k ověření mého argumentu skriptu a toto fungovalo perfektně. Děkuji! [[ "$ARG" =~ ^(true|false)$ ]] || { echo "Argument received invalid value" ; exit 1 ; }
  • Pokud ‚ hodláte vložit seznam shod do souboru, můžete také použít grep: egrep -q "^$WORD$" /tmp/words; [[ $? != 0 ]] && echo "Not found" || echo "OK".

odpověď

case $word in dog|cat|horse) echo yes;; *) echo no;; esac 

Odpověď

Co takhle:

#!/usr/bin/env bash WORD="$1" for w in dog cat horse do if [ "$w" == "$WORD" ] then yes=1 break fi done; [ "$yes" == "1" ] && echo "$WORD is in the list" || echo "$WORD is not in the list" 

Potom:

$ a.sh cat cat is in the list $ a.sh bob bob is not in the list 

Odpovědět

if (echo "$set" | fgrep -q "$WORD") 

Komentáře

  • Opatrně, toto vrátí hodnotu true, pokud je $WORD prázdný, bude odpovídat, pokud WORD=ca nebo WORD=og nebo podobné a předpokládám, že jste mysleli echo ${set[@]}.
  • stačí přidat -w to grep, aby se zabránilo neúplným slovům

Odpovědět

K tomu můžete definovat funkci bash:

function word_valid() { if [ "$1" != "cat" -a "$1" != "dog" -a "$1" != "horse" ];then echo no else echo yes fi } 

Pak použijte jednoduše takto:

word_valid cat 

Odpovědět

Hledal jsem „jednořádkové“ řešení k ověření argumentu mého skriptu a použil jsem Joseph R. answer výše nahoru s:

[[ "$ARG" =~ ^(true|false)$ ]] || { echo "Argument received invalid value" ; exit 1 ; }

Odpověď

Vy mohl použít fgrep k určení všech povolených slov:

if $(echo "$WORD" | fgrep -wq -e dog -e cat -e horse) ; then echo yes else echo no fi 

Příznak -w odpovídá pouze plným slovům, -q příznak umožňuje tichý provoz (protože potřebujeme pouze návratovou hodnotu příkazu if) a každý -e vzor určuje vzor povolit.

fgrep je verze grepu, která místo shody s regulárním výrazem provádí normální shodu řetězců. Pokud máte grep, měli byste mít fgrep, ale pokud ne, je to stejné jako použití grep s příznakem -F (stačí tedy fgrep -wq výše nahradit grep -Fwq).

Odpověď

Toto pro mě fungovalo:

#!/bin/bash phrase=(cat dog parrot cow horse) findthis=parrot for item in ${phrase[*]} do test "$item" == "$findthis" && { echo "$findthis found!"; break; } done 

Odpověď

Možná budete chtít vložit seznam slov do souboru, pokud jej často měníte nebo chcete být sdíleny více skripty. A pokud bude seznam příliš dlouhý na správu ve skriptu, možná budete muset slova vložit do souboru. Potom můžete říci

if fgrep –qx "$WORD" word_list 

Komentáře

  • ne, ‚ nechci mít svůj seznam v souboru

Odpověď

Pokud jsou slova seznamem, kde jsou hodnoty odděleny novým řádkem, můžete:

WORDS="$(ls -1)" if echo "${WORDS}" | grep --quiet --line-regexp --fixed-strings "${WORD}"; then echo yes else echo no fi 

Odpověď

Právě jsem měl stejný problém a našel jsem překvapivě srozumitelné řešení, které nevyžaduje žádné znalosti regulárního výrazu.

Upozorňujeme, že níže zobrazené řešení může být pouze bash, protože nemám ponětí o rozdílech mezi bash a jinými mušlemi. Manuál bash dále varuje, že tento druh porovnávání vzorů je pomalý, pokud je řetězec, který by měl odpovídat, dlouhý.

WORD=abc [[ "$WORD" == @(def|abc|ghi|foo|barbaz) ]] && echo Word is in set. 

Jak to funguje?Nechci zde opakovat velké části příručky bash, ale podle mých vlastních slov:

Pokud je použit binární operátor == s složeným příkazem [[, slovo na pravé straně operátoru prochází porovnáváním vzorů, jak je vysvětleno v sekci “ Porovnávání vzorů “ v příručce bash. Dále se za těchto podmínek při párování předpokládá, že je nastavena volba prostředí extglob (bez ohledu na skutečné nastavení); toto je klíčový bod pro pochopení výše uvedeného.

Ale co když slova ve vaší sadě již obsahují znaky, které mají zvláštní význam pro porovnávání vzorů, nahrazování příkazů a další rozšíření? Náprava je snadná: Stačí použít něco jako

[[ "$WORD" == @("a*"|abc|"?ghi"|"$DontExpandMe"|barbaz) ]] && echo Word is in set. 

Zjistil jsem, že je to velmi snadné, srozumitelné a efektivní (pokud je $WORD krátký) řešení, které nemá vedlejší účinky nebo je da bláznivé jako metody založené na set.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *