docs: def analyze_bash_vars(job_input_file, job_homedir):
      '''
      This function examines the input file, and calculates variables to
      instantiate in the shell environment. It is called right before starting the
      execution of an app in a worker.
  
      For each input key, we want to have
      $var
      $var_filename
      $var_prefix
         remove last dot (+gz), and/or remove patterns
      $var_path
         $HOME/in/var/$var_filename
  
      For example,
      $HOME/in/genes/A.txt
                     B.txt
  
      export genes=('{"$dnanexus_link": "file-xxxx"}' '{"$dnanexus_link": "file-yyyy"}')
      export genes_filename=("A.txt" "B.txt")
      export genes_prefix=("A" "B")
      export genes_path=("$HOME/in/genes/A.txt" "$HOME/in/genes/B.txt")
  
      If there are patterns defined in the input spec, then the prefix respects them.
      Here are several examples, where the patterns are:
         *.bam, *.bwa-index.tar.gz, foo*.sam, z*ra.sam
  
      file name                prefix     matches
      foo.zed.bam              foo.zed    *.bam
      xxx.bwa-index.tar.gz     xxx        *.bwa-index.tar.gz
      food.sam                 food       foo*.sam
      zebra.sam                zebra      z*ra.sam
      xx.c                     xx
      xx.c.gz                  xx
  
      The only patterns we recognize are of the form x*.y. For example:
        legal    *.sam, *.c.py,  foo*.sam,  a*b*c.baz
        ignored  uu.txt x???.tar  mon[a-z].py
      '''
      _, file_entries, rest_hash = get_job_input_filenames(job_input_file)
      patterns_dict = get_input_spec_patterns()
  
      # Note: there may be multiple matches, choose the shortest prefix.
      def get_prefix(basename, key):
          best_prefix = None
          patterns = patterns_dict.get(key)
          if patterns is not None:
              for pattern in patterns:
                  if fnmatch.fnmatch(basename, pattern):
                      _, _, right_piece = pattern.rpartition("*")
                      best_prefix = choose_shorter_string(best_prefix, basename[:-len(right_piece)])
          if best_prefix is not None:
              return best_prefix
          else:
              # no matching rule
              parts = os.path.splitext(basename)
              if parts[1] == ".gz":
                  parts = os.path.splitext(parts[0])
              return parts[0]
  
      def factory():
          return {'handler': [], 'basename': [],  'prefix': [], 'path': []}
      file_key_descs = collections.defaultdict(factory)
      rel_home_dir = get_input_dir(job_homedir)
      for key, entries in list(file_entries.items()):
          for entry in entries:
              filename = entry['trg_fname']
              basename = os.path.basename(filename)
              prefix = get_prefix(basename, key)
              k_desc = file_key_descs[key]
              k_desc['handler'].append(entry['handler'])
              k_desc['basename'].append(basename)
              k_desc['prefix'].append(prefix)
              k_desc['path'].append(os.path.join(rel_home_dir, filename))
      return file_key_descs, rest_hash