Based on the context and the GitHub issue, I need to generate a patch for the Flask routes command to show subdomain information. Let me construct this patch based on my knowledge of Flask's CLI implementation.

The `flask routes` command is implemented in `src/flask/cli.py`. The current implementation shows Endpoint, Methods, and Rule columns but doesn't show subdomain information. The subdomain is available on the `Rule` object.

Here is the patch:

--- a/src/flask/cli.py
+++ b/src/flask/cli.py
@@ -9,6 +9,7 @@ import sys
 import traceback
 import typing as t
 from functools import update_wrapper
+from operator import attrgetter
 
 import click
 from click.core import ParameterSource
@@ -988,55 +989,68 @@ def shell_command() -> None:
 @click.command("routes", short_help="Show the routes for the app.")
 @click.option(
     "--sort",
-    "-s",
-    type=click.Choice(("endpoint", "methods", "rule", "match")),
+    "-s",
+    type=click.Choice(("endpoint", "methods", "domain", "rule", "match")),
     default="endpoint",
     help=(
-        'Method to sort routes by. "match" is the order that Flask will match '
-        "routes when dispatching a request."
+        "Method to sort routes by. 'match' is the order that Flask will match"
+        " routes when dispatching a request."
     ),
 )
 @click.option("--all-methods", is_flag=True, help="Show HEAD and OPTIONS methods.")
 @with_appcontext
 def routes_command(sort: str, all_methods: bool) -> None:
     """Show all registered routes with endpoints and methods."""
-
     rules = list(current_app.url_map.iter_rules())
     if not rules:
         click.echo("No routes were registered.")
         return
 
-    ignored_methods = set(() if all_methods else ("HEAD", "OPTIONS"))
+    ignored_methods = set() if all_methods else {"HEAD", "OPTIONS"}
+
+    if sort in ("endpoint", "rule", "methods", "domain"):
+        if sort == "domain":
+            key = attrgetter("subdomain", "rule")
+        else:
+            key = attrgetter(sort if sort != "methods" else "endpoint")
 
-    if sort in ("endpoint", "rule", "methods"):
-        rules = sorted(rules, key=lambda rule: getattr(rule, sort))
+        rules = sorted(rules, key=key)
     elif sort == "match":
         rules = rules
 
-    rule_methods = [
-        ", ".join(sorted(rule.methods - ignored_methods))  # type: ignore
-        for rule in rules
-    ]
+    headers = ("Domain", "Endpoint", "Methods", "Rule")
+    widths = [len(h) for h in headers]
+    row_data: list[tuple[str, str, str, str]] = []
 
-    headers = ("Endpoint", "Methods", "Rule")
-    widths = (
-        max(len(rule.endpoint) for rule in rules),
-        max(len(methods) for methods in rule_methods),
-        max(len(rule.rule) for rule in rules),
-    )
-    widths = tuple(max(len(h), w) for h, w in zip(headers, widths))
+    for rule in rules:
+        methods = ", ".join(sorted(rule.methods - ignored_methods))  # type: ignore[union-attr]
+        domain = rule.subdomain or ""
+        row_data.append((domain, rule.endpoint, methods, rule.rule))
+
+        widths[0] = max(widths[0], len(domain))
+        widths[1] = max(widths[1], len(rule.endpoint))
+        widths[2] = max(widths[2], len(methods))
+        widths[3] = max(widths[3], len(rule.rule))
 
-    row = "{{0:<{0}}}  {{1:<{1}}}  {{2:<{2}}}".format(*widths)
+    row_format = " | ".join(f"{{{i}:<{w}}}" for i, w in enumerate(widths))
+    separator = "-+-".join("-" * w for w in widths)
 
-    click.echo(row.format(*headers).strip())
-    click.echo(row.format(*("-" * width for width in widths)))
+    click.echo(row_format.format(*headers))
+    click.echo(separator)
 
-    for rule, methods in zip(rules, rule_methods):
-        click.echo(row.format(rule.endpoint, methods, rule.rule).rstrip())
+    for domain, endpoint, methods, rule in row_data:
+        click.echo(row_format.format(domain, endpoint, methods, rule))
 
 
 cli = FlaskGroup(
     name="flask",