To execute a program that can return a non-zero result, you should wrap the call to exec in catch and check the contents of the -errorcode return option if you have an error:
set status 0
if {[catch {exec grep foo bar.txt} results options]} {
set details [dict get $options -errorcode]
if {[lindex $details 0] eq «CHILDSTATUS»} {
set status [lindex $details 2]
} else {
# Some kind of unexpected failure
}
}