27

With Perl you can check if an array contains a value

$ perl -e '@foo=(444,555,666); print 555 ~~ @foo ? "T" : "F"'
T

However with awk, this similar command is checking the array indexes rather than values

$ awk 'BEGIN {split("444 555 666", foo); print 555 in foo ? "T" : "F"}'
F

How can I check if an array contains a particular value with awk?

4
  • 1
    I believe your only option is to loop. Commented Nov 4, 2014 at 22:40
  • 4
    Like Etan says, you need a for-loop. You can achieve a somewhat flexible result by creating a new array (hash) with the values as keys, e.g.: awk 'BEGIN { split("444 555 666", foo); for(i=1; i<=length(foo); i++) bar[foo[i]]; print 555 in bar ? "T" : "F" }' Commented Nov 4, 2014 at 23:19
  • 3
    @Thor - Can't you just use for( i in foo ) bar[foo[i]] instead? Commented Nov 4, 2014 at 23:24
  • 3
    @n0741337: You are right, shorter and cleaner, so it becomes: awk 'BEGIN { split("444 555 666", foo); for(i in foo) bar[foo[i]]; print 555 in bar ? "T" : "F" }'. Commented Nov 4, 2014 at 23:27

5 Answers 5

34

Awk noob here. I digested Steven's answer and ended up with this hopefully easier to understand snippet below. There are 2 more subtle problems:

  • An Awk array is actually a dictionary. It's not ["value1", "value2"], it's more like {0: "value1", 1: "value2"}.
  • in checks for keys, and there is no built-in way to check for values.

So you have to convert your array (which is actually a dictionary) to a dictionary with the values as keys.

BEGIN {

    split("value1 value2", valuesAsValues)
    # valuesAsValues = {0: "value1", 1: "value2"}

    for (i in valuesAsValues) valuesAsKeys[valuesAsValues[i]] = ""
    # valuesAsKeys = {"value1": "", "value2": ""}
}

# Now you can use `in`
($1 in valuesAsKeys) {print}

For one-liners:

echo "A:B:C:D:E:F" | tr ':' '\n' | \
awk 'BEGIN{ split("A D F", parts); for (i in parts) dict[parts[i]]=""}  $1 in dict'
Sign up to request clarification or add additional context in comments.

Comments

0

what I do is structure my data to take advantage of what the language provides.

So instead of saying :

BEGIN {split("444 555 666", foo); .... }

say :

BEGIN { bar[ "444" ] ; ... }

or ala another suggestion:

BEGIN { 
  split("444 555 666", foo);
  for( i in FOO ) bar[foo[i]];
}

remember arrays in awk are really associative arrays.

Comments

0
BEGIN {
  split("value1 value2 value3", valueArray)
  # valueArray is {1: "value1", 2: "value2", 3: "value2"}
}
{
  # given $1 is the value to test for
  for (i in valueArray) {
    if ( $1 == valueArray[i] ) {
      print $1
      # OR 
      print "True"
      # ...
    }
  }
}

Comments

0

In the spirit of a one-liner (see Thamme's answer) that sticks more to the OP's perl reference (ternary operator):

echo -e "a\nb\nc" | awk '{t[$1]}END{print (("a" in t) ? "yes":"no")}' # prints yes, try with ("m" in t)

Comments

-1

gawk 'BEGIN { split("a b c d",parts); for (i in parts) dict[parts[i]]=1 } $1 in dict {print}' some.log

1 Comment

While this code may solve the question, including an explanation of how and why this solves the problem would really help to improve the quality of your post, and probably result in more up-votes. Remember that you are answering the question for readers in the future, not just the person asking now. Please edit your answer to add explanations and give an indication of what limitations and assumptions apply.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.