Shell Pipelines

I'm trying to understand this Shell line:

grep ^x06 ssh_known_hosts |
ssh-keygen -l -f -| 
\sed -e 's/^.*\(SHA256:\S\+\).*(\([^)]\+\))/\2: \1/' >fp
  • So with grep we are basically searching for the data ssh_unknown_hosts. What is ^x06 used for?
  • With the ssh-keygen command we are generating a SSH key with -l. What's the -f used for?
  • The last line I didn't get.

Solution 1:

grep is searching the file ssh_known_hosts for the line (or lines) starting with x06 (^ indicates a beginning of line in a regular expression) and outputs it.

From man ssh-keygen:

 ssh-keygen -l [-f input_keyfile]

[...]

 -l      Show fingerprint of specified public key file.  Private RSA1 keys
         are also supported.  For RSA and DSA keys ssh-keygen tries to
         find the matching public key file and prints its fingerprint.  If
         combined with -v, an ASCII art representation of the key is sup‐
         plied with the fingerprint.

So ssh-keygen -l -f - reads key from standard input (that is, from the line that has been output by grep) and outputs its fingerprint (- used as a filename indicates standard input).

The sed part is the most difficult. One needs to understand well regular expressions to understand what it does.

sed runs the command s/pattern/replacement/ on each line of input, that is, replaces pattern with replacement and copies the line to standard output. If the pattern is not found in the line, the line is copied unchanged.

The pattern sed is looking for is: ^.*\(SHA256:\S\+\).*(\([^)]\+\)). It is a regular expression of course.

It can be broken down as follows:

  • beginning of line (^), followed by zero or more of any characters (.*), followed by first group (the part between \( ... \); we get to the details later), followed by zero or more of any characters (.*), followed by second group, which is enclosed in literal parentheses (\( ... \)).

  • The first group is SHA256:\S\+. This means a literal string SHA256:, followed by one or more non-space characters (\S\+) - however, it should be noted that not all sed implementations will support \S as an indication of non-space character. So first group matches SHA256: followed by any characters, up to the first space.

  • The second group is [^)]\+, that is, one or more characters that are not equal to the closing parenthesis. Taking into account that the entire group is placed in parentheses, the second group matches any string placed in parentheses, up to the closing parenthesis.

Summing up, sed searches in line for a pattern consisting of SHA256: plus any non-space characters, and then any string placed in parentheses, with anything between them.

The matched pattern is replaced with \2: \1 which is the text matching the second group (\2), colon, space and the text matching the first group (\1).

For example, if ssh-keygen output contains a line like

begin something SHA256:123456 middle something (text inside parens) end something

sed will replace that line with

text inside parens: SHA256:123456 end something

Lines that don't contain the pattern won't be changed.