--- /dev/null
+#!/bin/bash
+
+declare -a data
+cur_data=""
+seperator=""
+valid_count=0
+
+required_fields=(byr iyr eyr hgt hcl ecl pid)
+
+check_year() {
+ value=$1
+ min=$2
+ max=$3
+
+ if [ $value -ge $min ] && [ $value -le $max ]; then
+ exit 0
+ fi
+ exit 1
+}
+
+check_height() {
+ value=$1
+ units=${value:$((${#value}-2)):2}
+ value=${value:0:$((${#value}-2))}
+ case $units in
+ in)
+ if [ $value -ge 59 ] && [ $value -le 76 ]; then
+ exit 0
+ fi
+ ;;
+ cm)
+ if [ $value -ge 150 ] && [ $value -le 193 ]; then
+ exit 0
+ fi
+ ;;
+ *)
+ ;;
+ esac
+ exit 1
+}
+
+check_hair() {
+ value=$1
+
+ if [ ${value:0:1} != "#" ]; then
+ exit 1
+ fi
+
+ if [[ $value =~ /^[a-f0-9]{6}$/ ]]; then
+ exit 1
+ fi
+
+ exit 0
+}
+
+check_eyes() {
+ colour="$1"
+ case $colour in
+ amb|blu|brn|gry|grn|hzl|oth)
+ exit 0
+ ;;
+ *)
+ exit 1
+ ;;
+ esac
+ exit 1
+}
+
+check_data() {
+ local -n record=$1
+ for x in ${!record[@]}; do
+ value=${record[$x]}
+ case $x in
+ byr)
+ if ! ( check_year $value 1920 2002 ); then
+ exit 1
+ fi
+ ;;
+ iyr)
+ if ! ( check_year $value 2010 2020 ); then
+ exit 1
+ fi
+ ;;
+ eyr)
+ if ! ( check_year $value 2020 2030 ); then
+ exit 1
+ fi
+ ;;
+ hgt)
+ if ! ( check_height $value ); then
+ exit 1
+ fi
+ ;;
+ hcl)
+ if ! ( check_hair $value ); then
+ exit 1
+ fi
+ ;;
+ ecl)
+ if ! ( check_eyes $value ); then
+ exit 1
+ fi
+ ;;
+ pid)
+ value=${record[$x]}
+ if [ ${#value} -ne 9 ]; then
+ exit 1
+ fi
+ ;;
+ *)
+ ;;
+ esac
+ done
+
+ exit 0
+}
+
+exec 3<input.txt
+
+while read -u 3 line; do
+ if [ "$line" = "" ]; then
+ data+=("$cur_data")
+ seperator=""
+ cur_data=""
+ continue
+ fi
+ cur_data="${cur_data}${seperator}$line"
+ seperator=" "
+done
+
+check_fields() {
+ local -n record=$1
+ for field in ${required_fields[@]}; do
+ if ! [ ${record[$field]+a} ]; then
+ exit 1
+ fi
+ done
+
+ exit 0
+}
+
+# on the last line, if cur_data isn't empty, add that to the array
+if [ "$cur_data" != "" ]; then
+ data+=("$cur_data")
+fi
+
+for (( i=0; i<${#data[@]}; i++ )); do
+ record="${data[$i]}"
+ declare -A kvp
+ for field in $record; do
+ key=${field%:*}
+ value=${field#*:}
+ kvp[$key]=$value
+ done
+ if ( check_fields kvp ); then
+ if ( check_data kvp ); then
+ valid_count=$((valid_count+1))
+ fi
+ fi
+ unset kvp
+done
+
+echo "$valid_count valid entries"