(command.CommandList
  children: [
    (command.ShAssignment
      pairs: [
        (assign_pair
          lhs: (sh_lhs_expr.Name name:tid)
          op: assign_op.Equal
          rhs: {(DQ <'hostkey rotate'>)}
          spids: [7]
        )
      ]
    )
    (command.ShAssignment
      pairs: [
        (assign_pair
          lhs: (sh_lhs_expr.Name name:HOSTKEY_TYPES)
          op: assign_op.Equal
          rhs: {(DQ <'ecdsa-sha2-nistp256 ssh-ed25519 ssh-rsa ssh-dss'>)}
          spids: [16]
        )
      ]
    )
    (C {<rm>} {<-f>} {($ Id.VSub_DollarName '$OBJ') </hkr.> <Id.Lit_Star '*'>} 
      {($ Id.VSub_DollarName '$OBJ') </ssh_proxy.orig>}
    )
    (command.Simple
      words: [{<grep>} {<-vi>} {(SQ <hostkey>)} {($ Id.VSub_DollarName '$OBJ') </sshd_proxy>}]
      redirects: [
        (redir.Redir
          op: <Id.Redir_Great '>'>
          fd: -1
          arg_word: {($ Id.VSub_DollarName '$OBJ') </sshd_proxy.orig>}
        )
      ]
    )
    (command.Simple
      words: [{<echo>} {(DQ <'UpdateHostkeys=yes'>)}]
      redirects: [
        (redir.Redir
          op: <Id.Redir_DGreat '>>'>
          fd: -1
          arg_word: {($ Id.VSub_DollarName '$OBJ') </ssh_proxy>}
        )
      ]
    )
    (C {<rm>} {($ Id.VSub_DollarName '$OBJ') </known_hosts>})
    (C {<trace>} {(DQ <'prepare hostkeys'>)})
    (command.ShAssignment
      pairs: [(assign_pair lhs:(sh_lhs_expr.Name name:nkeys) op:assign_op.Equal rhs:{<0>} spids:[73])]
    )
    (command.ShAssignment
      pairs: [
        (assign_pair
          lhs: (sh_lhs_expr.Name name:all_algs)
          op: assign_op.Equal
          rhs: {(DQ )}
          spids: [76]
        )
      ]
    )
    (command.ForEach
      iter_name: k
      iter_words: [
        {
          (command_sub
            left_token: <Id.Left_Backtick '`'>
            command_list: 
              (command.CommandList
                children: [(C {(${ Id.VSub_Name SSH)} {<-Q>} {<key-plain>})]
              )
          )
        }
      ]
      do_arg_iter: F
      body: 
        (command.DoGroup
          children: [
            (command.AndOr
              ops: [Id.Op_DPipe]
              children: [
                (C {(${ Id.VSub_Name SSHKEYGEN)} {<-qt>} {($ Id.VSub_DollarName '$k')} {<-f>} 
                  {($ Id.VSub_DollarName '$OBJ') </hkr.> ($ Id.VSub_DollarName '$k')} {<-N>} {(SQ )}
                )
                (C {<fatal>} {(DQ <'ssh-keygen '> ($ Id.VSub_DollarName '$k'))})
              ]
            )
            (command.Simple
              words: [
                {<echo>}
                {(DQ <'Hostkey '> ($ Id.VSub_DollarName '$OBJ') </hkr.> (${ Id.VSub_Name k))}
              ]
              redirects: [
                (redir.Redir
                  op: <Id.Redir_DGreat '>>'>
                  fd: -1
                  arg_word: {($ Id.VSub_DollarName '$OBJ') </sshd_proxy.orig>}
                )
              ]
            )
            (command.ShAssignment
              pairs: [
                (assign_pair
                  lhs: (sh_lhs_expr.Name name:nkeys)
                  op: assign_op.Equal
                  rhs: 
                    {
                      (command_sub
                        left_token: <Id.Left_Backtick '`'>
                        command_list: 
                          (command.CommandList
                            children: [
                              (C {<expr>} {($ Id.VSub_DollarName '$nkeys')} {<Id.Lit_Other '+'>} {<1>})
                            ]
                          )
                      )
                    }
                  spids: [149]
                )
              ]
            )
            (command.AndOr
              ops: [Id.Op_DPipe]
              children: [
                (C {<test>} {(DQ <x> ($ Id.VSub_DollarName '$all_algs'))} {<Id.Lit_Equals '='>} {(DQ <x>)})
                (command.ShAssignment
                  pairs: [
                    (assign_pair
                      lhs: (sh_lhs_expr.Name name:all_algs)
                      op: assign_op.Equal
                      rhs: {(DQ (${ Id.VSub_Name all_algs) <','>)}
                      spids: [178]
                    )
                  ]
                )
              ]
            )
            (command.ShAssignment
              pairs: [
                (assign_pair
                  lhs: (sh_lhs_expr.Name name:all_algs)
                  op: assign_op.Equal
                  rhs: {(DQ (${ Id.VSub_Name all_algs) ($ Id.VSub_DollarName '$k'))}
                  spids: [187]
                )
              ]
            )
          ]
        )
    )
    (command.ShFunction
      name: dossh
      body: 
        (command.BraceGroup
          children: [
            (command.AndOr
              ops: [Id.Op_DPipe]
              children: [
                (C {(${ Id.VSub_Name SSH)} {<-F>} {($ Id.VSub_DollarName '$OBJ') </ssh_proxy>} 
                  {(DQ ($ Id.VSub_At '$@'))} {<x>} {<true>}
                )
                (C {<fail>} {(DQ <'ssh '> ($ Id.VSub_At '$@') <' failed'>)})
              ]
            )
          ]
        )
    )
    (command.ShFunction
      name: expect_nkeys
      body: 
        (command.BraceGroup
          children: [
            (command.ShAssignment
              pairs: [
                (assign_pair
                  lhs: (sh_lhs_expr.Name name:_expected)
                  op: assign_op.Equal
                  rhs: {($ Id.VSub_Number '$1')}
                  spids: [246]
                )
              ]
            )
            (command.ShAssignment
              pairs: [
                (assign_pair
                  lhs: (sh_lhs_expr.Name name:_message)
                  op: assign_op.Equal
                  rhs: {($ Id.VSub_Number '$2')}
                  spids: [250]
                )
              ]
            )
            (command.AndOr
              ops: [Id.Op_DPipe]
              children: [
                (command.ShAssignment
                  pairs: [
                    (assign_pair
                      lhs: (sh_lhs_expr.Name name:_n)
                      op: assign_op.Equal
                      rhs: 
                        {
                          (command_sub
                            left_token: <Id.Left_Backtick '`'>
                            command_list: 
                              (command.CommandList
                                children: [
                                  (command.Pipeline
                                    children: [
                                      (C {<wc>} {<-l>} {($ Id.VSub_DollarName '$OBJ') </known_hosts>})
                                      (C {<awk>} {(SQ <'{ print $1 }'>)})
                                    ]
                                    negated: F
                                  )
                                ]
                              )
                          )
                        }
                      spids: [254]
                    )
                  ]
                )
                (C {<fatal>} {(DQ <'wc failed'>)})
              ]
            )
            (command.AndOr
              ops: [Id.Op_DPipe]
              children: [
                (C {<Id.Lit_LBracket '['>} {(DQ <x> ($ Id.VSub_DollarName '$_n'))} {<Id.Lit_Equals '='>} 
                  {(DQ <x> ($ Id.VSub_DollarName '$_expected'))} {<Id.Lit_RBracket ']'>}
                )
                (C {<fail>} 
                  {
                    (DQ ($ Id.VSub_DollarName '$_message') <' (got '> ($ Id.VSub_DollarName '$_n') 
                      <' wanted '> ($ Id.VSub_DollarName '$_expected') <')'>
                    )
                  }
                )
              ]
            )
          ]
        )
    )
    (command.ShFunction
      name: check_key_present
      body: 
        (command.BraceGroup
          children: [
            (command.ShAssignment
              pairs: [
                (assign_pair
                  lhs: (sh_lhs_expr.Name name:_type)
                  op: assign_op.Equal
                  rhs: {($ Id.VSub_Number '$1')}
                  spids: [322]
                )
              ]
            )
            (command.ShAssignment
              pairs: [
                (assign_pair
                  lhs: (sh_lhs_expr.Name name:_kfile)
                  op: assign_op.Equal
                  rhs: {($ Id.VSub_Number '$2')}
                  spids: [326]
                )
              ]
            )
            (command.AndOr
              ops: [Id.Op_DAmp]
              children: [
                (C {<test>} {(DQ <x> ($ Id.VSub_DollarName '$_kfile'))} {<Id.Lit_Equals '='>} {(DQ <x>)})
                (command.ShAssignment
                  pairs: [
                    (assign_pair
                      lhs: (sh_lhs_expr.Name name:_kfile)
                      op: assign_op.Equal
                      rhs: {(DQ ($ Id.VSub_DollarName '$OBJ') </hkr.> (${ Id.VSub_Name _type) <.pub>)}
                      spids: [345]
                    )
                  ]
                )
              ]
            )
            (command.AndOr
              ops: [Id.Op_DPipe]
              children: [
                (command.ShAssignment
                  pairs: [
                    (assign_pair
                      lhs: (sh_lhs_expr.Name name:_kpub)
                      op: assign_op.Equal
                      rhs: 
                        {
                          (command_sub
                            left_token: <Id.Left_Backtick '`'>
                            command_list: 
                              (command.CommandList
                                children: [
                                  (command.Simple
                                    words: [
                                      {<awk>}
                                      {(DQ </> ($ Id.VSub_DollarName '$_type') <' /'>) 
                                        (SQ <' { print $2 }'>)
                                      }
                                    ]
                                    redirects: [
                                      (redir.Redir
                                        op: <Id.Redir_Less '<'>
                                        fd: -1
                                        arg_word: {($ Id.VSub_DollarName '$_kfile')}
                                      )
                                    ]
                                  )
                                ]
                              )
                          )
                        }
                      spids: [356]
                    )
                  ]
                )
                (C {<fatal>} {(DQ <'awk failed'>)})
              ]
            )
            (command.Simple
              words: [
                {<fgrep>}
                {(DQ ($ Id.VSub_DollarName '$_kpub'))}
                {($ Id.VSub_DollarName '$OBJ') </known_hosts>}
              ]
              redirects: [(redir.Redir op:<Id.Redir_Great '>'> fd:-1 arg_word:{</dev/null>})]
            )
          ]
        )
    )
    (C {<cp>} {($ Id.VSub_DollarName '$OBJ') </sshd_proxy.orig>} 
      {($ Id.VSub_DollarName '$OBJ') </sshd_proxy>}
    )
    (C {<verbose>} {(DQ <'learn hostkey with StrictHostKeyChecking=no'>)})
    (command.Simple
      redirects: [
        (redir.Redir
          op: <Id.Redir_Great '>'>
          fd: -1
          arg_word: {($ Id.VSub_DollarName '$OBJ') </known_hosts>}
        )
      ]
    )
    (C {<dossh>} {<-oHostKeyAlgorithms> <Id.Lit_Equals '='> <ssh-ed25519>} 
      {<-oStrictHostKeyChecking> <Id.Lit_Equals '='> <no>}
    )
    (C {<expect_nkeys>} {<1>} {(DQ <'unstrict connect keys'>)})
    (command.AndOr
      ops: [Id.Op_DPipe]
      children: [
        (C {<check_key_present>} {<ssh-ed25519>})
        (C {<fail>} {(DQ <"unstrict didn't learn key">)})
      ]
    )
    (C {<verbose>} {(DQ <'learn additional hostkeys'>)})
    (C {<dossh>} {<-oStrictHostKeyChecking> <Id.Lit_Equals '='> <yes>} 
      {<-oHostKeyAlgorithms> <Id.Lit_Equals '='> ($ Id.VSub_DollarName '$all_algs')}
    )
    (C {<expect_nkeys>} {($ Id.VSub_DollarName '$nkeys')} {(DQ <'learn hostkeys'>)})
    (command.AndOr
      ops: [Id.Op_DPipe]
      children: [(C {<check_key_present>} {<ssh-rsa>}) (C {<fail>} {(DQ <"didn't learn keys">)})]
    )
    (command.ForEach
      iter_name: k
      iter_words: [
        {
          (command_sub
            left_token: <Id.Left_Backtick '`'>
            command_list: 
              (command.CommandList
                children: [(C {(${ Id.VSub_Name SSH)} {<-Q>} {<key-plain>})]
              )
          )
        }
      ]
      do_arg_iter: F
      body: 
        (command.DoGroup
          children: [
            (C {<verbose>} {(DQ <'learn additional hostkeys, type='> ($ Id.VSub_DollarName '$k'))})
            (C {<dossh>} {<-oStrictHostKeyChecking> <Id.Lit_Equals '='> <yes>} 
              {<-oHostKeyAlgorithms> <Id.Lit_Equals '='> ($ Id.VSub_DollarName '$k') <Id.Lit_Comma ','> 
                ($ Id.VSub_DollarName '$all_algs')
              }
            )
            (C {<expect_nkeys>} {($ Id.VSub_DollarName '$nkeys')} 
              {(DQ <'learn hostkeys '> ($ Id.VSub_DollarName '$k'))}
            )
            (command.AndOr
              ops: [Id.Op_DPipe]
              children: [
                (C {<check_key_present>} {($ Id.VSub_DollarName '$k')})
                (C {<fail>} {(DQ <"didn't learn "> ($ Id.VSub_DollarName '$k'))})
              ]
            )
          ]
        )
    )
    (C {<verbose>} {(DQ <'learn changed non-primary hostkey'>)})
    (C {<mv>} {($ Id.VSub_DollarName '$OBJ') </hkr.ssh-rsa.pub>} 
      {($ Id.VSub_DollarName '$OBJ') </hkr.ssh-rsa.pub.old>}
    )
    (C {<rm>} {<-f>} {($ Id.VSub_DollarName '$OBJ') </hkr.ssh-rsa>})
    (command.AndOr
      ops: [Id.Op_DPipe]
      children: [
        (C {(${ Id.VSub_Name SSHKEYGEN)} {<-qt>} {<ssh-rsa>} {<-f>} 
          {($ Id.VSub_DollarName '$OBJ') </hkr.ssh-rsa>} {<-N>} {(SQ )}
        )
        (C {<fatal>} {(DQ <'ssh-keygen '> ($ Id.VSub_DollarName '$k'))})
      ]
    )
    (C {<dossh>} {<-oStrictHostKeyChecking> <Id.Lit_Equals '='> <yes>} 
      {<-oHostKeyAlgorithms> <Id.Lit_Equals '='> ($ Id.VSub_DollarName '$all_algs')}
    )
    (C {<expect_nkeys>} {($ Id.VSub_DollarName '$nkeys')} {(DQ <'learn hostkeys'>)})
    (command.AndOr
      ops: [Id.Op_DAmp]
      children: [
        (C {<check_key_present>} {<ssh-rsa>} {($ Id.VSub_DollarName '$OBJ') </hkr.ssh-rsa.pub.old>})
        (C {<fail>} {(DQ <'old key present'>)})
      ]
    )
    (command.AndOr
      ops: [Id.Op_DPipe]
      children: [(C {<check_key_present>} {<ssh-rsa>}) (C {<fail>} {(DQ <"didn't learn changed key">)})]
    )
    (C {<verbose>} {(DQ <'learn new primary hostkey'>)})
    (command.AndOr
      ops: [Id.Op_DPipe]
      children: [
        (C {(${ Id.VSub_Name SSHKEYGEN)} {<-qt>} {<ssh-rsa>} {<-f>} 
          {($ Id.VSub_DollarName '$OBJ') </hkr.ssh-rsa-new>} {<-N>} {(SQ )}
        )
        (C {<fatal>} {(DQ <'ssh-keygen '> ($ Id.VSub_DollarName '$k'))})
      ]
    )
    (command.Subshell
      command_list: 
        (command.CommandList
          children: [
            (command.Sentence
              child: (C {<cat>} {($ Id.VSub_DollarName '$OBJ') </sshd_proxy.orig>})
              terminator: <Id.Op_Semi _>
            )
            (C {<echo>} {<HostKey>} {($ Id.VSub_DollarName '$OBJ') </hkr.ssh-rsa-new>})
          ]
        )
      redirects: [
        (redir.Redir
          op: <Id.Redir_Great '>'>
          fd: -1
          arg_word: {($ Id.VSub_DollarName '$OBJ') </sshd_proxy>}
        )
      ]
    )
    (C {<dossh>} {<-oStrictHostKeyChecking> <Id.Lit_Equals '='> <yes>} 
      {<-oHostKeyAlgorithms> <Id.Lit_Equals '='> <ssh-rsa> <Id.Lit_Comma ','> 
        ($ Id.VSub_DollarName '$all_algs')
      }
    )
    (C {<expect_nkeys>} 
      {
        (command_sub
          left_token: <Id.Left_Backtick '`'>
          command_list: 
            (command.CommandList
              children: [(C {<expr>} {($ Id.VSub_DollarName '$nkeys')} {<Id.Lit_Other '+'>} {<1>})]
            )
        )
      } {(DQ <'learn hostkeys'>)}
    )
    (command.AndOr
      ops: [Id.Op_DPipe]
      children: [(C {<check_key_present>} {<ssh-rsa>}) (C {<fail>} {(DQ <'current key missing'>)})]
    )
    (command.AndOr
      ops: [Id.Op_DPipe]
      children: [
        (C {<check_key_present>} {<ssh-rsa>} {($ Id.VSub_DollarName '$OBJ') </hkr.ssh-rsa-new.pub>})
        (C {<fail>} {(DQ <'new key missing'>)})
      ]
    )
    (C {<verbose>} {(DQ <'rotate primary hostkey'>)})
    (C {<cp>} {($ Id.VSub_DollarName '$OBJ') </sshd_proxy.orig>} 
      {($ Id.VSub_DollarName '$OBJ') </sshd_proxy>}
    )
    (C {<mv>} {($ Id.VSub_DollarName '$OBJ') </hkr.ssh-rsa.pub>} 
      {($ Id.VSub_DollarName '$OBJ') </hkr.ssh-rsa.pub.old>}
    )
    (C {<mv>} {($ Id.VSub_DollarName '$OBJ') </hkr.ssh-rsa-new.pub>} 
      {($ Id.VSub_DollarName '$OBJ') </hkr.ssh-rsa.pub>}
    )
    (C {<mv>} {($ Id.VSub_DollarName '$OBJ') </hkr.ssh-rsa-new>} 
      {($ Id.VSub_DollarName '$OBJ') </hkr.ssh-rsa>}
    )
    (C {<dossh>} {<-oStrictHostKeyChecking> <Id.Lit_Equals '='> <yes>} 
      {<-oHostKeyAlgorithms> <Id.Lit_Equals '='> <ssh-rsa> <Id.Lit_Comma ','> 
        ($ Id.VSub_DollarName '$all_algs')
      }
    )
    (C {<expect_nkeys>} {($ Id.VSub_DollarName '$nkeys')} {(DQ <'learn hostkeys'>)})
    (command.AndOr
      ops: [Id.Op_DAmp]
      children: [
        (C {<check_key_present>} {<ssh-rsa>} {($ Id.VSub_DollarName '$OBJ') </hkr.ssh-rsa.pub.old>})
        (C {<fail>} {(DQ <'old key present'>)})
      ]
    )
    (command.AndOr
      ops: [Id.Op_DPipe]
      children: [(C {<check_key_present>} {<ssh-rsa>}) (C {<fail>} {(DQ <"didn't learn changed key">)})]
    )
    (C {<verbose>} {(DQ <'check rotate primary hostkey'>)})
    (C {<dossh>} {<-oStrictHostKeyChecking> <Id.Lit_Equals '='> <yes>} 
      {<-oHostKeyAlgorithms> <Id.Lit_Equals '='> <ssh-rsa>}
    )
    (C {<expect_nkeys>} {<1>} {(DQ <'learn hostkeys'>)})
    (command.AndOr
      ops: [Id.Op_DPipe]
      children: [(C {<check_key_present>} {<ssh-rsa>}) (C {<fail>} {(DQ <"didn't learn changed key">)})]
    )
  ]
)