Since you want to see the output from your echo command, you need to separate the stdout output from the return (exit) code:
#!/bin/bash
func(){
local a=$1 b=$2
echo "$a" # stdout output
echo "$b"
if (( a > b )) # see below for how this could be simplified.
then
return 0 # set exit code
else
return 1
fi
}
c=1 d=4
while ! func $c $d
do
((c++))
done
That way, you're free to use the function directly (prefixed with ! to negate the test's outcome), without a command substitution, and let its return (exit) code drive the outcome of the while loop condition (an exit code of 0 meaning success, any other meaning failure).
By using just ! func $c $d as the condition, func's stdout output is simply printed as is.
Addendum: Billy Wayne McCann's answer points out that there's no strict need to use explicit return statements to set the exit code (but there's no need to use test[1]).
(( a > b )) can be used by itself as the last statement in the function, to set the exit code implicitly:
If there's no explicit return statement, it is a function's last command that sets its exit code (the same applies analogously to scripts in the absence of an exit statement).
(( ... )) sets the exit code to 1, if ... evaluates to 0, and 1 otherwise (any non-negative result). A Boolean expression such as a > b results in 1, if the expression is true, and 0 otherwise. Therefore, (( a > b )) by itself does the same thing implicitly that the above if statement does explicitly:
func(){
local a=$1 b=$2
echo "$a" # stdout output
echo "$b"
(( a > b )) # exit code implicitly set to 0, if test *succeeds*, 1 otherwise
}
[1] Using test or [ ... ] is the POSIX-compliant way to evaluate a condition. Unless your code must be POSIX-compliant, Bash's [[ ... ]] and (( ... )) (for arithmetic Boolean tests) are the better choice - see https://stackoverflow.com/a/29320710/45375