it-swarm.com.de

Wie überprüfe ich, ob in BASH eine Variable in einer Liste vorhanden ist?

Ich versuche in Bash ein Skript zu schreiben, das die Gültigkeit einer Benutzereingabe überprüft.
Ich möchte die Eingabe (sprich Variable x) an eine Liste gültiger Werte anpassen.

was ich im Moment gemacht habe, ist:

for item in $list
do
    if [ "$x" == "$item" ]; then
        echo "In the list"
        exit
    fi
done

Meine Frage ist, ob es einen einfacheren Weg gibt, dies zu tun,
so etwas wie eine list.contains(x) für die meisten Programmiersprachen.

Zusatz:
Die Liste lautet:

list="11 22 33"

mein Code gibt die Nachricht nur für diese Werte zurück, da list als Array und nicht als String behandelt wird Alle Zeichenfolgenmanipulationen werden 1 validiert.

103
Ofir Farchy
[[ $list =~ (^|[[:space:]])$x($|[[:space:]]) ]] && echo 'yes' || echo 'no'

oder eine Funktion erstellen:

contains() {
    [[ $1 =~ (^|[[:space:]])$2($|[[:space:]]) ]] && exit(0) || exit(1)
}

um es zu benutzen:

contains aList anItem
echo $? # 0: match, 1: failed
128
chemila

Matvey hat recht, aber Sie sollten $ x zitieren und jede Art von "Leerzeichen" (z. B. neue Zeile) mit berücksichtigen

[[ $list =~ (^|[[:space:]])"$x"($|[[:space:]]) ]] && echo 'yes' || echo 'no' 

d.h.

# list_include_item "10 11 12" "2"
function list_include_item {
  local list="$1"
  local item="$2"
  if [[ $list =~ (^|[[:space:]])"$item"($|[[:space:]]) ]] ; then
    # yes, list include item
    result=0
  else
    result=1
  fi
  return $result
}

ende dann

`list_include_item "10 11 12" "12"`  && echo "yes" || echo "no"

oder

if `list_include_item "10 11 12" "1"` ; then
  echo "yes"
else 
  echo "no"
fi

Beachten Sie, dass Sie bei Variablen "" verwenden müssen:

`list_include_item "$my_list" "$my_item"`  && echo "yes" || echo "no"
27
Oriettaxx

Sie können (* Wildcards) auch außerhalb einer case-Anweisung verwenden, wenn Sie doppelte Klammern verwenden:

string='My string';

if [[ $string == *My* ]]
then
echo "It's there!";
fi
13

Die einfachste Lösung für IMHO besteht darin, die ursprüngliche Zeichenfolge mit einem Leerzeichen voranstellen und anhängen und mit [[ ]] gegen eine Regex überprüfen.

haystack='foo bar'
needle='bar'

if [[ " $haystack " =~ .*\ $needle\ .* ]]; then
    ...
fi

dies ist nicht falsch positiv für Werte mit Werten, die die Nadel als Teilstring enthalten, z. mit einem Heuhaufen foo barbaz.

(Das Konzept wird schamlos aus der hasClass()- Methode von JQuery gestohlen)

11
blaimi

wie wäre es mit

echo $list|grep $x

sie können entweder die Ausgabe oder $? der obigen Zeile überprüfen, um die Entscheidung zu treffen.

10
Kent

Wenn die Liste im Skript festgelegt ist, gefällt mir Folgendes am besten:

validate() {
    grep -F -q -x "$1" <<EOF
item 1
item 2
item 3
EOF
}

Verwenden Sie dann validate "$x", um zu testen, ob $x zulässig ist.

Wenn Sie einen Einzeiler wünschen und sich nicht um Leerzeichen in Artikelnamen kümmern, können Sie Folgendes verwenden (beachten Sie -w anstelle von -x):

validate() { echo "11 22 33" | grep -F -q -w "$1"; }

Anmerkungen:

  • Dies ist mit POSIX sh kompatibel.
  • validate macht nicht akzeptiert Teilstrings (entfernen Sie die Option -x für grep, wenn Sie dies wünschen).
  • Die Variable validate interpretiert ihr Argument als festen String und nicht als regulären Ausdruck .__ (Entfernen Sie die Option -F für grep, wenn Sie dies wünschen).

Beispielcode zur Ausführung der Funktion:

for x in "item 1" "item2" "item 3" "3" "*"; do
    echo -n "'$x' is "
    validate "$x" && echo "valid" || echo "invalid"
done
5
Søren Løvborg

Ich finde es einfacher, das Formular echo $LIST | xargs -n1 echo | grep $VALUE wie unten gezeigt zu verwenden:

LIST="ITEM1 ITEM2"
VALUE="ITEM1"
if [ -n "`echo $LIST | xargs -n1 echo | grep -e \"^$VALUE`$\" ]; then
    ...
fi

Dies funktioniert für eine durch Leerzeichen getrennte Liste, Sie können sie jedoch an jeden anderen Begrenzer (wie :) anpassen, indem Sie Folgendes tun:

LIST="ITEM1:ITEM2"
VALUE="ITEM1"
if [ -n "`echo $LIST | sed 's|:|\\n|g' | grep -e \"^$VALUE`$\"`" ]; then
   ...
fi

Beachten Sie, dass der " erforderlich ist, damit der Test funktioniert.

5

Nutzen Sie die Schlüssel von assoziativen Arrays . Ich würde davon ausgehen, dass diese Outperformate sowohl das Übereinstimmen als auch das Schleifen von Regex/Mustern verbessern, obwohl ich es noch nicht erstellt habe.

declare -A list=( [one]=1 [two]=two [three]='any non-empty value' )
for value in one two three four
do
    echo -n "$value is "
    # a missing key expands to the null string, 
    # and we've set each interesting key to a non-empty value
    [[ -z "${list[$value]}" ]] && echo -n '*not* '
    echo "a member of ( ${!list[*]} )"
done

Ausgabe:

one is a member of ( one two three )
two is a member of ( one two three )
three is a member of ( one two three )
four is *not* a member of ( one two three )
4
RubyTuesdayDONO

Wenn Ihre Liste von Werten im Skript hartcodiert werden soll, ist es relativ einfach, case zu testen. Hier ein kurzes Beispiel, das Sie an Ihre Anforderungen anpassen können:

for item in $list
do
    case "$x" in
      item1|item2)
        echo "In the list"
        ;;
      not_an_item)
        echo "Error" >&2
        exit 1
        ;;
    esac
done

Wenn die Liste zur Laufzeit eine Array-Variable ist, passt eine der anderen Antworten wahrscheinlich besser.

4
Toby Speight

Beispiele

$ in_list super test me out
NO

$ in_list "super dude" test me out
NO

$ in_list "super dude" test me "super dude"
YES

# How to use in another script
if [ $(in_list $1 OPTION1 OPTION2) == "NO" ]
then
  echo "UNKNOWN type for param 1: Should be OPTION1 or OPTION2"
  exit;
fi

in_list

function show_help()
{
  IT=$(CAT <<EOF

  usage: SEARCH_FOR {ITEM1} {ITEM2} {ITEM3} ...

  e.g. 

  a b c d                    -> NO
  a b a d                    -> YES
  "test me" how "test me"    -> YES

  )
  echo "$IT"
  exit
}

if [ "$1" == "help" ]
then
  show_help
fi

if [ "$#" -eq 0 ]; then
  show_help
fi

SEARCH_FOR=$1
shift;

for ITEM in "[email protected]"
do
  if [ "$SEARCH_FOR" == "$ITEM" ]
  then
    echo "YES"
    exit;
  fi
done

echo "NO"
1
Brad Parks

Angenommen, TARGET-Variable kann nur "binomial" oder "Regression" sein, dann würde Folgendes geschehen:

# Check for modeling types known to this script
if [ $( echo "${TARGET}" | egrep -c "^(binomial|regression)$" ) -eq 0 ]; then
    echo "This scoring program can only handle 'binomial' and 'regression' methods now." >&2
    usage
fi

Sie können der Liste weitere Zeichenfolgen hinzufügen, indem Sie sie mit | trennen (Pfeife) Zeichen.

Der Vorteil der Verwendung von egrep besteht darin, dass Sie die Groß-/Kleinschreibung (-i) problemlos hinzufügen oder komplexere Szenarien mit einem regulären Ausdruck prüfen können.

1
Tagar

Dies ist fast Ihr ursprünglicher Vorschlag, aber fast ein 1-Liner. Nicht so kompliziert wie andere gültige Antworten und nicht so abhängig von bash-Versionen (kann mit alten bashes funktionieren).

OK=0 ; MP_FLAVOURS="Vanilla lemon hazelnut straciatella"
for FLAV in $MP_FLAVOURS ; do [ $FLAV == $FLAVOR ] && { OK=1 ; break; } ; done
[ $OK -eq 0 ] && { echo "$FLAVOR not a valid value ($MP_FLAVOURS)" ; exit 1 ; }

Ich denke, mein Vorschlag kann immer noch verbessert werden, sowohl in der Länge als auch im Stil.

0
carnicer

Ich dachte, ich würde meine Lösung in die Liste aufnehmen.

# Checks if element "$1" is in array "$2"
# @NOTE:
#   Be sure that array is passed in the form:
#       "${ARR[@]}"
elementIn () {
    # shopt -s nocasematch # Can be useful to disable case-matching
    local e
    for e in "${@:2}"; do [[ "$e" == "$1" ]] && return 0; done
    return 1
}

# Usage:
list=(11 22 33)
item=22

if elementIn "$item" "${list[@]}"; then
    echo TRUE;
else
    echo FALSE
fi
# TRUE

item=44
elementIn $item "${list[@]}" && echo TRUE || echo FALSE
# FALSE
0
SamWN