7
\$\begingroup\$

Here is the working code (intended to be executed with perl -e '<code>' ~/.ssh/config):

Actual version:

while(<>){if(/^Host (.+)/){$_=$1;foreach $i(/([^ ]+)/g){$h{$i}=1}}}print "$_ " for keys %h;

Identical version with whitespace for reading:

while(<>) {
    if(/^Host (.+)/) {
        $_=$1;
        foreach $i(/([^ ]+)/g) {
            $h{$i}=1
        }
    }
}
print "$_ " for keys %h;

I'm sort of a perl newbie. Is $_=$1 kosher? Is there a straight-forward way to do this with a single regex? Is there anything else I should be doing better here?

Example input output:

For a config file with contents like this:

Host build
    HostName build.myserver.com
Host build build.myserver.com
    User ubuntu
    IdentityFile ~/.ssh/build
Host tunnel
    LocalForward 6397 redis.production.com:6379

The output should be (order is not required, trailing space is not required but acceptable):

build build.myserver.com tunnel 
\$\endgroup\$
8
\$\begingroup\$

I would use something like

perl -lane '@h{@F[1..$#F]}=()if/^Host\b/;END{$,=" ";print keys %h}' -- file

or

perl -lane '@h{ @F[ 1 .. $#F ] } = () if /^Host\b/;
            END {
                $, = " ";
                print keys %h;
            }' -- file
  • -l removes newlines from input and adds them to prints
  • -n runs the code for each line of the input
  • -a splits each line on whitespace into the @F array
  • the hash %h is populated by all the non-whitepsace strings following Host
  • at the end, all the keys are printed separated by space
\$\endgroup\$
  • 1
    \$\begingroup\$ Commenting some other things I learned from this answer that I didn't know previously: $#array returns the last index of an array, $, is the "output field separator" printed automatically between fields, END{} gives a block of code that is executed when exiting, useful for doing final one-time code while still using the -n option. \$\endgroup\$ – GrandOpener Jan 28 at 20:22
  • \$\begingroup\$ can shave a few characters there by switching to print "@{[ EXPR ]}" and using eof in place of an END block. And the spaces after -e and keys are optional. perl -lane'@h{@F[1..$#F]}=()if/^Host\b/;eof&&print"@{[keys%h]}"' -- file \$\endgroup\$ – Oh My Goodness Jan 31 at 13:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.