The reason why
$command =~ m/(!\w+\s?.+?)(?=!\w)/simg;
only returns one result is because you call it in scalar or void context, once. You either have to loop through the parts, or extract them all at once and then loop through each.
The latter approach look easier to me. It can be done by modifying your code like:
my @commands = $command =~ m/(!\w+\s?.+?)(?=!\w)/simg;
Except that you'll miss the last command because there's no "!word" pattern following it.
You can fix that by allowing that it's followed by either a new command, or the end of the string.
my @commands = $command =~ m/(!\w+\s?.+?)(?=!\w|\z)/simg;
n.b. The flags /i and /m are superfluous, and 1) there's nothing case sensitive and 2) there are no "^" or "$" meta characters that can change meaning.
Anyway, once you have the list of commands, you can go through them like
foreach my $command (@commands) {
...
}
and process them pretty much as you do now; reusing the
$command variable name (it's a different variable, regardless) allows to keep the remainder of the code as is.