Split a string of hostnames, expand from regex, return non-duplicated names in original order
To jump to the conclusion first, I would rewrite the function like this:

sub hostname_regex_expand {
    my ($patterns_ref, $hostnames_ref) = @_;
    my @patterns = @$patterns_ref;
    my @hostnames = $hostnames_ref ? @$hostnames_ref : get_hostlist();

    my %results;
    foreach my $pattern (@patterns) {
        my @found = grep(/$pattern/, @hostnames);
        @found = $pattern unless @found;
        @results{@found} = ();
    }

    return sort keys %results;
}


First of all, the original variable names were not so good: @target_list, %host_hash, and $host_string contain in the name their types (list, hash, string), which is not normal or necessary. What's worse is that @host_names and $host_name are storing host name patterns, not really host names.

In terms of the logic, instead of iterating over each hostname to try to see if it matches a pattern, it would be more straightforward to use a grep.

It seems you really want to use two list parameters:


List of patterns
List of hostnames


So I changed the function to take two list references, it's cleaner than the original.

I took a shortcut that you might not like: instead of adding matched hosts and patterns to @hosts, I use the %results map, and return the sorted keys. The title of your post (and the original) suggests that you want to preserve the original order. If that's a requirement, not a problem, we can refactor like this:

sub hostname_regex_expand {
    my ($patterns_ref, $hostnames_ref) = @_;
    my @patterns = @$patterns_ref;
    my @hostnames = $hostnames_ref ? @$hostnames_ref : get_hostlist();

    my @ordered;
    my %results;
    foreach my $pattern (@patterns) {
        my @found = grep(/$pattern/, @hostnames);
        @found = $pattern unless @found;
        foreach my $item (@found) {
            if (!$results{$item}) {
                push(@ordered, $item);
                $results{$item} = 1;
            }
        }
    }

    return @ordered;
}