Files
dotfiles/local/bin/x-open-ports

144 lines
3.4 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# List open (listened) ports in Markdown or JSON format.
#
# Modified by: Ismo Vuorinen <https://github.com/ivuorinen> 2020, 2025
# Originally from: https://www.commandlinefu.com/commands/view/8951
# Original author: https://www.commandlinefu.com/commands/by/wickedcpj
set -euo pipefail
FORMAT="markdown"
# Function to print help message
print_help()
{
cat << EOF
Usage: $(basename "$0") [OPTIONS]
List open (listened) ports in a formatted table (Markdown) or JSON.
Options:
--json Output results in JSON format instead of Markdown
--help Show this help message
Examples:
$(basename "$0") # List open ports as a Markdown table
$(basename "$0") --json # List open ports in JSON format
EOF
exit 0
}
# Function to print the Markdown table header
print_header()
{
echo "| User | Command | PID | Port |"
echo "|------------------|----------------------------|----------|---------|"
}
# Function to list open ports using lsof
list_open_ports_lsof()
{
lsof -i -P -n -sTCP:LISTEN +c 0 2> /dev/null | awk '
NR > 1 {
port = $9
sub(/.*:/, "", port) # Extract port number
printf "| %-16s | %-26s | %-8s | %-7s |\n", substr($3, 1, 16), substr($1, 1, 26), substr($2, 1, 8), port
}
' | sort -k3,3n | uniq
}
# Function to list open ports using ss (alternative)
list_open_ports_ss()
{
ss -ltpn 2> /dev/null | awk '
NR > 1 {
split($5, addr, ":")
port = addr[length(addr)]
user = $1
cmd = $7
sub(/users:\(\(/, "", cmd) # Cleanup command
sub(/\)\)/, "", cmd)
pid = "-"
match(cmd, /pid=([0-9]+)/, m)
if (m[1] != "") pid = m[1]
printf "| %-16s | %-26s | %-8s | %-7s |\n", substr(user, 1, 16), substr(cmd, 1, 26), substr(pid, 1, 8), port
}
' | sort -k3,3n | uniq
}
# Function to print JSON output
list_open_ports_json()
{
if command -v lsof &> /dev/null; then
lsof -i -P -n -sTCP:LISTEN +c 0 2> /dev/null | awk '
NR > 1 {
port = $9
sub(/.*:/, "", port) # Extract port number
printf "{\"user\": \"%s\", \"command\": \"%s\", \"pid\": \"%s\", \"port\": \"%s\"},\n", $3, $1, $2, port
}
' | sort -k3,3n | uniq | sed '$ s/,$//'
elif command -v ss &> /dev/null; then
ss -ltpn 2> /dev/null | awk '
NR > 1 {
split($5, addr, ":")
port = addr[length(addr)]
user = $1
cmd = $7
sub(/users:\(\(/, "", cmd)
sub(/\)\)/, "", cmd)
pid = "-"
match(cmd, /pid=([0-9]+)/, m)
if (m[1] != "") pid = m[1]
printf "{\"user\": \"%s\", \"command\": \"%s\", \"pid\": \"%s\", \"port\": \"%s\"},\n", user, cmd, pid, port
}
' | sort -k3,3n | uniq | sed '$ s/,$//'
else
echo "[]"
fi
}
# Function to determine available command
list_open_ports()
{
if [[ "$FORMAT" == "json" ]]; then
echo "["
list_open_ports_json
echo "]"
else
print_header
if command -v lsof &> /dev/null; then
list_open_ports_lsof
elif command -v ss &> /dev/null; then
list_open_ports_ss
else
echo "**Error:** Neither 'lsof' nor 'ss' is available."
exit 1
fi
fi
}
# Main function
main()
{
case "${1:-}" in
--json)
FORMAT="json"
;;
--help)
print_help
;;
"") ;;
*)
echo "Unknown option: $1"
print_help
;;
esac
list_open_ports
echo ""
}
main "$@"