From 82330c72a472e67d09b915caadfc1d15559bbc3b Mon Sep 17 00:00:00 2001 From: xraystyle Date: Fri, 6 Jun 2025 16:25:20 -0700 Subject: [PATCH 1/3] Implement -br flag for brief interface output. --- README.md | 4 +++ src/ip.py | 88 ++++++++++++++++++++++++++++++++---------------- test/commands.sh | 40 ++++++++++++++++++++++ 3 files changed, 103 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 72fb414..3c05ec5 100644 --- a/README.md +++ b/README.md @@ -44,8 +44,11 @@ Goal of this utility is to provide compatible CLI with [iproute2], supporting sa * `ip neigh help` * `bridge help` * `bridge link help` +* Options + * Brief output mode: `ip -br link` or `ip -br addr` * Link module (Interfaces) * List local interfaces `ip link` + * List interfaces in brief format `ip -br link` * Show one interface `ip link show en0` * Shutdown interface `ip link set dev en0 down` * Start interface `ip link set dev en0 up` @@ -65,6 +68,7 @@ Goal of this utility is to provide compatible CLI with [iproute2], supporting sa * IPv6 (NDP) neighbours are being flushed for all interfaces * Address module * List all addresses `ip addr` + * List all addresses in brief format `ip -br addr` * List IPv4 addresses `ip -4 addr` * List IPv6 addresses `ip -6 addr` * Add address to interface `ip addr add 10.0.0.5/24 dev en0` diff --git a/src/ip.py b/src/ip.py index cf104dc..ea4d912 100755 --- a/src/ip.py +++ b/src/ip.py @@ -90,7 +90,7 @@ def parse_ifconfig(res, af, address): return links -def link_addr_show(argv, af, json_print, pretty_json, address): +def link_addr_show(argv, af, json_print, pretty_json, address, brief=False): if len(argv) > 0 and argv[0] == "dev": argv.pop(0) if len(argv) > 0: @@ -113,33 +113,59 @@ def link_addr_show(argv, af, json_print, pretty_json, address): if json_print: return json_dump(links, pretty_json) - for l in links: - print("%d: %s: <%s> mtu %d status %s" % ( - l["ifindex"], l["ifname"], ",".join(l["flags"]), l["mtu"], - l["operstate"] - )) - print( - " link/" + l["link_type"] + - ((" " + l["address"]) if "address" in l else "") + - ((" brd " + l["broadcast"]) if "broadcast" in l else "") - ) - for a in l.get("addr_info", []): + if brief: + # Brief format: interface_name STATUS ip_addresses... + for l in links: + # Interface name (left-padded to align) + line = "%-16s " % l["ifname"] + + # Status + line += "%-8s" % l["operstate"] + + # Add addresses + addrs = [] + for a in l.get("addr_info", []): + addr_str = "%s/%d" % (a["local"], a["prefixlen"]) + addrs.append(addr_str) + + # For link output, show MAC address + if not address and "address" in l: + addrs.insert(0, l["address"]) + + # Add minimum 7 spaces before first address, then single space between addresses + if addrs: + line += " " + " ".join(addrs) + else: + line += "" + print(line) + else: + for l in links: + print("%d: %s: <%s> mtu %d status %s" % ( + l["ifindex"], l["ifname"], ",".join(l["flags"]), l["mtu"], + l["operstate"] + )) print( - " %s %s" % (a["family"], a["local"]) + - ((" peer %s" % a["address"]) if "address" in a else "") + - "/%d" % (a["prefixlen"]) + - ((" brd " + a["broadcast"]) if "broadcast" in a else "") + " link/" + l["link_type"] + + ((" " + l["address"]) if "address" in l else "") + + ((" brd " + l["broadcast"]) if "broadcast" in l else "") ) + for a in l.get("addr_info", []): + print( + " %s %s" % (a["family"], a["local"]) + + ((" peer %s" % a["address"]) if "address" in a else "") + + "/%d" % (a["prefixlen"]) + + ((" brd " + a["broadcast"]) if "broadcast" in a else "") + ) return True # Help -def do_help(argv=None, af=None, json_print=None, pretty_json=None): +def do_help(argv=None, af=None, json_print=None, pretty_json=None, brief=None): perror("Usage: ip [ OPTIONS ] OBJECT { COMMAND | help }") perror("where OBJECT := { link | addr | route | neigh }") perror(" OPTIONS := { -V[ersion] | -j[son] | -p[retty] | -c[olor] |") - perror(" -4 | -6 }") + perror(" -br[ief] | -4 | -6 }") perror(HELP_ADDENDUM) exit(255) @@ -181,7 +207,7 @@ def do_help_neigh(): # Route Module @help_msg(do_help_route) -def do_route(argv, af, json_print, pretty_json): +def do_route(argv, af, json_print, pretty_json, brief): if not argv or ( any_startswith(["show", "lst", "list"], argv[0]) and len(argv) == 1 ): @@ -392,13 +418,13 @@ def do_route_get(argv, af, json_print, pretty_json): # Addr Module @help_msg(do_help_addr) -def do_addr(argv, af, json_print, pretty_json): +def do_addr(argv, af, json_print, pretty_json, brief): if not argv: argv.append("show") if any_startswith(["show", "lst", "list"], argv[0]): argv.pop(0) - return do_addr_show(argv, af, json_print, pretty_json) + return do_addr_show(argv, af, json_print, pretty_json, brief) elif "add".startswith(argv[0]) and len(argv) >= 3: argv.pop(0) return do_addr_add(argv, af) @@ -410,8 +436,8 @@ def do_addr(argv, af, json_print, pretty_json): return True -def do_addr_show(argv, af, json_print, pretty_json): - return link_addr_show(argv, af, json_print, pretty_json, True) +def do_addr_show(argv, af, json_print, pretty_json, brief): + return link_addr_show(argv, af, json_print, pretty_json, True, brief) def do_addr_add(argv, af): @@ -464,13 +490,13 @@ def do_addr_del(argv, af): # Link module @help_msg(do_help_link) -def do_link(argv, af, json_print, pretty_json): +def do_link(argv, af, json_print, pretty_json, brief): if not argv: argv.append("show") if any_startswith(["show", "lst", "list"], argv[0]): argv.pop(0) - return do_link_show(argv, af, json_print, pretty_json) + return do_link_show(argv, af, json_print, pretty_json, brief) elif "set".startswith(argv[0]): argv.pop(0) return do_link_set(argv, af) @@ -479,8 +505,8 @@ def do_link(argv, af, json_print, pretty_json): return True -def do_link_show(argv, af, json_print, pretty_json): - return link_addr_show(argv, af, json_print, pretty_json, False) +def do_link_show(argv, af, json_print, pretty_json, brief): + return link_addr_show(argv, af, json_print, pretty_json, False, brief) def do_link_set(argv, af): @@ -533,7 +559,7 @@ def do_link_set(argv, af): # Neigh module @help_msg(do_help_neigh) -def do_neigh(argv, af, json_print, pretty_json): +def do_neigh(argv, af, json_print, pretty_json, brief): if not argv: argv.append("show") @@ -673,6 +699,7 @@ def main(argv): af = -1 # default / both json_print = False pretty_json = False + brief = False while argv and argv[0].startswith("-"): # Turn --opt into -opt @@ -684,6 +711,9 @@ def main(argv): elif argv[0] == "-4": af = 4 argv.pop(0) + elif "-brief".startswith(argv[0]) or argv[0] == "-br": + brief = True + argv.pop(0) elif "-color".startswith(argv[0].split("=")[0]): if "never" not in argv[0].split("="): perror("iproute2mac: Color option is not implemented") @@ -711,7 +741,7 @@ def main(argv): argv.pop(0) # Functions return true or terminate with exit(255) # See help_msg and do_help* - return cmd_func(argv, af, json_print, pretty_json) + return cmd_func(argv, af, json_print, pretty_json, brief) perror('Object "{}" is unknown, try "ip help".'.format(argv[0])) exit(1) diff --git a/test/commands.sh b/test/commands.sh index 47f7529..b390ddd 100755 --- a/test/commands.sh +++ b/test/commands.sh @@ -111,6 +111,32 @@ $ip_cmd a s ! $ip_cmd addr asdf +## brief format tests + +# Test basic -br addr show +$ip_cmd -br addr show | grep -E "^lo[0-9]* +[A-Z]+ +" + +# Test -br a shorthand +$ip_cmd -br a | grep -E "^lo[0-9]* +[A-Z]+ +" + +# Test -br with specific device +$ip_cmd -br addr show dev lo0 | grep -E "^lo0 +[A-Z]+ +" + +# Test -br with -4 (IPv4 only) +$ip_cmd -4 -br addr show | grep -E "^lo[0-9]* +[A-Z]+ +" | grep "127.0.0.1" + +# Test -br with -6 (IPv6 only) +$ip_cmd -6 -br addr show | grep -E "^lo[0-9]* +[A-Z]+ +" | grep "::1" + +# Test -br with -j (JSON output should override brief) +$ip_cmd -br -j addr show | perl -MJSON -e 'decode_json()' + +# Test order: -br before command +$ip_cmd -br addr show | grep -E "^lo[0-9]* +[A-Z]+ +" + +# Test order: -br after command (should also work) +$ip_cmd addr -br show | grep -E "^lo[0-9]* +[A-Z]+ +" + # link @@ -134,6 +160,20 @@ $ip_cmd l s | grep mtu ! $ip_cmd link asdf +## link brief format tests + +# Test basic -br link show +$ip_cmd -br link show | grep -E "^lo[0-9]* +[A-Z]+ +" + +# Test -br l shorthand +$ip_cmd -br l | grep -E "^lo[0-9]* +[A-Z]+ +" + +# Test -br with specific device +$ip_cmd -br link show lo0 | grep -E "^lo0 +[A-Z]+ +" + +# Test -br with -j (JSON output should override brief) +$ip_cmd -br -j link show | perl -MJSON -e 'decode_json()' + # neigh $ip_cmd nei help 2>&1 >/dev/null | grep "Usage: ip neighbour" From 4ffa4a954177d0cf5ba2d1bd1af0fc2f1a141da9 Mon Sep 17 00:00:00 2001 From: xraystyle Date: Fri, 6 Jun 2025 17:02:20 -0700 Subject: [PATCH 2/3] remove unnecessary else. --- src/ip.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ip.py b/src/ip.py index ea4d912..27f83b0 100755 --- a/src/ip.py +++ b/src/ip.py @@ -135,8 +135,6 @@ def link_addr_show(argv, af, json_print, pretty_json, address, brief=False): # Add minimum 7 spaces before first address, then single space between addresses if addrs: line += " " + " ".join(addrs) - else: - line += "" print(line) else: for l in links: From 92fdfacd28796caeec321433a85f5a8427c061bc Mon Sep 17 00:00:00 2001 From: xraystyle Date: Tue, 12 Aug 2025 15:28:46 -0700 Subject: [PATCH 3/3] Make requested fixes, update changelog in README. --- README.md | 5 +++++ src/ip.py | 33 ++++++++++++++------------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 5f4e724..1215533 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,11 @@ Goal of this utility is to provide compatible CLI with [iproute2], supporting sa * List bridges (with pretty print): `bridge -j -p link show` ## Changelog +
+ HEAD +- Added `--brief` option for show commands (https://github.com/brona/iproute2mac/issues/42, PR https://github.com/brona/iproute2mac/pull/69) +
+
v1.6.0 diff --git a/src/ip.py b/src/ip.py index d6be863..cd91339 100755 --- a/src/ip.py +++ b/src/ip.py @@ -90,7 +90,7 @@ def parse_ifconfig(res, af, address): return links -def link_addr_show(argv, af, json_print, pretty_json, color, address, brief=False): +def link_addr_show(argv, af, json_print, pretty_json, color, address, brief): if len(argv) > 0 and argv[0] == "dev": argv.pop(0) if len(argv) > 0: @@ -113,9 +113,9 @@ def link_addr_show(argv, af, json_print, pretty_json, color, address, brief=Fals if json_print: return json_dump(links, pretty_json) - if brief: - # Brief format: interface_name STATUS ip_addresses... - for l in links: + for l in links: + if brief: + # Brief format: interface_name STATUS ip_addresses... # Interface name (left-padded to align) ifname_colored = colorize_ifname(color, l["ifname"]) ifname_padding = max(0, 16 - len(l["ifname"])) @@ -140,8 +140,7 @@ def link_addr_show(argv, af, json_print, pretty_json, color, address, brief=Fals if addrs: line += " " + " ".join(addrs) print(line) - else: - for l in links: + else: print("%d: %s: <%s> mtu %d status %s" % ( l["ifindex"], colorize_ifname(color, l["ifname"]), @@ -166,7 +165,7 @@ def link_addr_show(argv, af, json_print, pretty_json, color, address, brief=Fals # Help -def do_help(argv=None, af=None, json_print=None, pretty_json=None, color=None): +def do_help(argv=None, af=None, json_print=None, pretty_json=None, color=None, brief=None): perror("Usage: ip [ OPTIONS ] OBJECT { COMMAND | help }") perror("where OBJECT := { link | addr | route | neigh }") perror(" OPTIONS := { -V[ersion] | -j[son] | -p[retty] | -c[olor] |") @@ -212,7 +211,7 @@ def do_help_neigh(): # Route Module @help_msg(do_help_route) -def do_route(argv, af, json_print, pretty_json, color): +def do_route(argv, af, json_print, pretty_json, color, brief): if not argv or ( any_startswith(["show", "lst", "list"], argv[0]) and len(argv) == 1 ): @@ -437,7 +436,7 @@ def do_route_get(argv, af, json_print, pretty_json, color): # Addr Module @help_msg(do_help_addr) -def do_addr(argv, af, json_print, pretty_json, color, brief=False): +def do_addr(argv, af, json_print, pretty_json, color, brief): if not argv: argv.append("show") @@ -455,7 +454,7 @@ def do_addr(argv, af, json_print, pretty_json, color, brief=False): return True -def do_addr_show(argv, af, json_print, pretty_json, color, brief=False): +def do_addr_show(argv, af, json_print, pretty_json, color, brief): return link_addr_show(argv, af, json_print, pretty_json, color, True, brief) @@ -509,7 +508,7 @@ def do_addr_del(argv, af): # Link module @help_msg(do_help_link) -def do_link(argv, af, json_print, pretty_json, color, brief=False): +def do_link(argv, af, json_print, pretty_json, color, brief): if not argv: argv.append("show") @@ -524,7 +523,7 @@ def do_link(argv, af, json_print, pretty_json, color, brief=False): return True -def do_link_show(argv, af, json_print, pretty_json, color, brief=False): +def do_link_show(argv, af, json_print, pretty_json, color, brief): return link_addr_show(argv, af, json_print, pretty_json, color, False, brief) @@ -578,7 +577,7 @@ def do_link_set(argv, af): # Neigh module @help_msg(do_help_neigh) -def do_neigh(argv, af, json_print, pretty_json, color): +def do_neigh(argv, af, json_print, pretty_json, color, brief): if not argv: argv.append("show") @@ -735,7 +734,7 @@ def main(argv): elif argv[0] == "-4": af = 4 argv.pop(0) - elif "-brief".startswith(argv[0]) or argv[0] == "-br": + elif "-brief".startswith(argv[0]): brief = True argv.pop(0) elif "-color".startswith(argv[0].split("=")[0]): @@ -770,11 +769,7 @@ def main(argv): argv.pop(0) # Functions return true or terminate with exit(255) # See help_msg and do_help* - # Pass brief parameter only to commands that support it (addr and link) - if cmd in ["address", "link"]: - return cmd_func(argv, af, json_print, pretty_json, color_scheme, brief) - else: - return cmd_func(argv, af, json_print, pretty_json, color_scheme) + return cmd_func(argv, af, json_print, pretty_json, color_scheme, brief) perror('Object "{}" is unknown, try "ip help".'.format(argv[0])) exit(1)