Drush 9 has removed dynamic site aliases. Site aliases are hardcoded in YAML files rather than declared in PHP. Sadly, that means that many tricks you could do with the declaration of the site aliases are no longer available.
The only grouping possible is based on the YAML filename. So for example, with the Acquia Cloud Site Factory site aliases generated by the 'blt recipes:aliases:init:acquia' command, you can run a command on the same site across different environments.
But what you can't do is run a command on all the sites in one environment.
One use case for this is checking whether a module is enabled on any sites, so you know that it's safe to remove it from the codebase.
Currently, this is quite a laborious process, as 'drush pm-list' needs to be run for each site.
With environment aliases, this would be a one liner:
drush @hypothetical-env-alias pm-list | ag some_module
('ag' is the very useful silver searcher unix command, which is almost the same as the also excellent 'ack' but faster, and both are much better than grep.)
While site aliases are fixed, they can be altered with Drush hooks. I considered that these might allow something to dynamically declare aliases, or a command option. There's an example of altering aliases with a hook in the Drush code.
In the meantime, a much simpler solution is to use xargs, which I have recently found is extremely useful in all sorts of situations. Because this allows you to run one command multiple times with a set of parameters, all you need to do is pass it a list of site aliases. Fortunately, the 'drush sa' command has lots of formatting options, and one of them gives us just what we need, a list of aliases with one on each line:
drush sa --format=list
That gives us all the aliases, and we probably don't want that. So here's where ag first comes in to play, as we can filter the list, for example, to only run on live sites (I'm using my ACSF aliases here as an example):
drush sa --format=list| ag 01live
Now we have a filtered list of aliases, and we can feed that into xargs:
drush sa --format=list| ag 01live | xargs -I % drush % pm-list
Normally, xargs puts the input parameter at the end of its command, but here we want it inserted just after the 'drush' command. The -I parameter allows us to specify a placeholder where the input parameter goes, so:
xargs -I % drush % pm-list
says that we want the site name to go where the '%' is, and means that that xargs will run:
drush SITE-ALIAS pm-list
with each value it receives, in this case, each site alias.
Another thing we will do with xargs is set the -t parameter, which outputs each actual command it executes on STDERR. That acts as a heading in the output, so we can clearly see which site is outputting what.
Finally, we can use ag a second time to filter the module list down to just the module we want to find out about:
drush sa --format=list | ag live | xargs -t -I % drush % pml | ag some_module
The nice thing about the -t parameter is that as it's STDERR, it's not affected by the final pipe to ag for filtering output. So the output will consist of the drush command for the site, followed by the filtered output.
And hey presto.
In conclusion: dynamic site aliases in Drush were nice, but the maintainers removed them (as far as I can gather) because they were a mess to implement, and removing them vastly simplified things. Doing the equivalent with xargs took a bit of figuring out, but once you know how to do it, it's actually a much more powerful way to work with multiple sites at once.