Let's restructure your require_line script a little to help you out.
First, we can get rid of the useless cat | grep. Second, we can use
grep's intrinsic behavior to indicate success or failure of the search for
KEY, as well as printing the key, if found, to stdout.
require_line(){
local KEY="$1"
local FILE="/tmp/myfile"
if grep "$KEY" "$FILE"
then
return 0
else
printf 'Key not found in:\n\n"%s"\n\nKey: "%s"\n' "$(cat "$FILE")" "$KEY" >&2
return 1
fi
}
This leverages the built-in behavior of grep. If the key is found, grep prints the matching line, and returns success.
Otherwise the else branch is taken, and a message is printed indicating that the key wasn't found. Further, in the case when grep fails, the error message is
printed to stderr so that the error message won't be mistaken for a valid
match found in $FILE.
You could further modify require_line to accept a filename as the $2
parameter by changing the line to read local FILE="$2" and then passing the
desired filename each time you invoke require_line.
Now, with that in place....
Do you really need to store each VALUEn for KEYn, or do you just need to ensure that
they are all present?
Now that you have a require_line function that cleanly returns a success or
failure value, you could simply AND all your tests together. As soon as
any one of them fails, the overall test will fail.
Assuming you do need the actual match values, the long-winded way to do it would be:
if value1=$(require_line "key1") &&
value2=$(require_line "key2") &&
value3=$(require_line "key3")
then
printf "%s\n" "$value1" "$value2" "$value3"
else
printf "One or more keys failed.\n" >&2
fi
That wil get tedious if you have numerous keys to check for. Using an array may be
better:
#!/usr/bin/env bash
require_line(){
local KEY="$1"
local FILE="/tmp/myfile" # or perhaps "$2"
if grep "$KEY" "$FILE"
then
return 0
else
printf 'Key not found in:\n\n"%s"\n\nKey: "%s"\n' "$(cat "$FILE")" "$KEY" >&2
return 1
fi
}
declare keys=("this" "is" "a" "test" "\." "keyN")
N=${#keys[@]}
declare values=()
j=0
while [ $j -lt $N ] && values[$j]="$(require_line "${keys[j]}")"
do
j=$(($j+1))
done
if [ $j -lt $N ]
then
printf 'error: found only %d keys out of %d:\n' $j $N
printf ' "%s"\n' "${values[@]}"
fi
Running that code with some sample data:
$ cat /tmp/myfile
this is a test.
$ ./test.sh
Key not found in:
"this is a test."
Key: "keyN"
error: found only 5 keys out of 6:
"this is a test."
"this is a test."
"this is a test."
"this is a test."
"this is a test."
""
Lastly, if you really only need to verify that all the keys are present without needing to know what the match values are, the array-oriented code above could be simplified to simply loop until all keys are found, or to abort at the first key that is found to be missing.
set -Eand anERRtrap, but I think that you're doing that wrong in the first place: better have thatrequire_linefunction set the variable itself, rather than being called in a subshell:require_line(){ local -n v=$1; ...; v=$INFO; }; ... require_line VALUE1 myKey1; ...(you can also do that portably withevalinstead of using variable references, but your Q is taggedbash)