On Linux, we might sometimes want to choose an unused TCP port randomly. This occurs from time to time on a server, when the administrator wants to expose an HTTP port for a user. Or, you just need an available port for IPC. Let’s make it happen with pure bash scripting.

We would take apart the function step by step in the following paragraphs.

Tirst step is to obtain a list of occupied ports, which can be accomplished by command

ss is a tool for investigating sockets, which prints out ports currently used in the form of a table:

Argument -Htan controls the printing style of ss. -H removes table header; -t lists only TCP ports; -a lists all ports, including listening and unlistening ones; -n enforces ports to be printed numerically . The command produces an output like:

We then use some string manipulation tools to extract the port numbers:

Here, awk '{print \$4}' selects the 4th item (e.g., 0.0.0.0:17500) from each line. cut -d':' -f2 splits each item with : and prints out the second part (e.g., 17500). sort -u sorts the items and removes duplicated ones.

Now we’ve got the list of unavailable ports. We might name it as LIST2 for simplicity. The next step is to create another list LIST1 by “inversing” LIST2. By “inversing” we mean LIST1 (disjointly) unioning LIST2 would be equal to FULLLIST (all legal ports).

FULLLIST can be obtained easily with seq "1025" "65535" | sort. The “inverse” operation, meanwhile, can be achieved using comm.

Simply, comm takes two files FILE1 and FILE2 as input, and produces output with three columns:

• Column 1 contains lines unique to FILE1;
• Column 2 contains lines unique to FILE2;
• Column 3 contains lines common to both files.

Apparently we only needs the first column, so use -23 to suppress the other two ones. Put them together as:

The syntax <(command) is known as process substitution. It is equivalent to:

• Spawn command in current shell and pipe its stdout to /dev/fd/<some number>;
• Substitute <(...) with /dev/fd/<some number>.

The last step, we further incorporate the command into a convenient function.

The function receives an argument N, shuffles the available port numbers, and choose N ports from the list.

Code is available at hsfzxjy/bashi on Github.