To properly redirect both the error and output streams to /dev/null, thereby suppressing the error message, you need to group the whole exec command:
{ exec 3<>/dev/tcp/127.0.0.1/9091; } > /dev/null 2>&1 || PORT_IS_FREE="yes"
exec
is a shell builtin, so it is hard to predict for me how it will behave, however I assume that even though it is able to treat <
and >
specially, the whole operation is still carried out in several steps, the streams of only the last of which get redirected.
Someone who knows more about the workings of exec
might be able to shed some light on this.
EDIT: I do not know why you needed brace-grouping for your variable assignment since it's a single command, but you can still use braces in conjunction with my examples if you want to, instead of the bare assignment I used.
As for ignoring the error, you could terminate the command after the redirection with ;
instead of using its exit status via ||
:
{ exec 3<>/dev/tcp/127.0.0.1/9091; } > /dev/null 2>&1 ; PORT_IS_FREE="yes"
Of course, in this case, there is the issue that you will not be able to catch any other error either. I just tried and the exit status is 1 after the error in question happens. If other codes are returned on different errors (which I doubt actually, since 1 is a very generic error code), you could test for 1.
EDIT: This solution also comes with the benefit of not exiting when code 1 is returned after the exec
, when set -e
is used:
{ exec 3<>/dev/tcp/127.0.0.1/9091; } > /dev/null 2>&1 || [ "$?" = 1 ] && PORT_IS_FREE="yes"
Otherwise, you might use grep
to try and match the error message, which is more reliable in my opinion:
socketOpenOutput="$({ exec 3<>/dev/tcp/127.0.0.1/9091; } 2>&1`)"
socketOpenErrorCode="$?"
if [ "$socketOpenErrorCode" != 0 ]; then
if ! echo "$socketOpenOutput" | grep 'connect\s*:\s*Connection refused' >/dev/null; then
echo "An unexpected error happened when opening the socket!"
exit 1
fi
fi
PORT_IS_FREE="yes"
This one, however, does not work well with set -e
.