This requires your bash have networking support compiled in (some distros don't, or didn't in the past), I'm not sure why you wouldn't use nmap, or even netcat: `nc -z $my_host_to_scan 1-1023`
It's kind of cheating to use perl for some of it, don't you think? I know this was just an experiment, and the actual networking part is pure bash, but the title is still misleading.
Still, this is certainly interesting and not something I'd considered.
1. we launch a new bash process to actually run the code (in this case, connect to a host) and store its ID so that we know how to kill it
2. we immediately launch a second process (the block { ... } &), whose only job is to wait for X seconds and then kill the first process
3. then we wait for the first process to end (either because it just finished, or because it was killed before it could) and return its return code.
function alarm() {
timeout=$1; shift; | this just copies the value from the first argument and removes that from the argument list
bash -c "$@" & | here we launch the first process, as in (1) above, passing it all the remaining arguments
pid=$! | .. and store its ID
{ | so, this is the second process
sleep $timeout | we wait the given number of seconds
kill $pid 2> /dev/null | and then we kill the first process, if it still exists
} &
wait $pid 2> /dev/null | 'wait' blocks the execution of the function until the first process terminates, and puts its return value into $?
return $? | this just returns the same that the first process did, so that the caller can know if it was successful or not
}
backgrounding a job to sleep/kill a pid isn't necessarily a great idea imho. here, if the port in question is open then then you will pass the wait relatively quickly, but you still have a timer set to kill the pid. A short timer probably won't cause an issue, but the longer you wait the more likely it becomes that the kernel will assign that pid to a new process that you probably don't want killed. especially if you are launching two new pids for each possible port.
I considered that, but didn't have time to think about a proper solution. Using bash's own job control instead of regular kill would probably be better.
13 comments
[ 1.9 ms ] story [ 62.6 ms ] thread1. we launch a new bash process to actually run the code (in this case, connect to a host) and store its ID so that we know how to kill it
2. we immediately launch a second process (the block { ... } &), whose only job is to wait for X seconds and then kill the first process
3. then we wait for the first process to end (either because it just finished, or because it was killed before it could) and return its return code.