def EvalWordToString(self, word, do_fnmatch=False, do_ere=False): """ Args: word: CompoundWord Used for redirect arg, ControlFlow arg, ArithWord, BoolWord, etc. do_fnmatch is true for case $pat and RHS of [[ == ]]. pat="*.py" case $x in $pat) echo 'matches glob pattern' ;; "$pat") echo 'equal to glob string' ;; # must be glob escaped esac TODO: Raise AssertionError if it has ExtGlobPart. """ if word.tag == word_e.EmptyWord: return value.Str('') part_vals = [] for p in word.parts: self._EvalWordPart(p, part_vals, quoted=False) strs = [] for part_val in part_vals: if part_val.tag == part_value_e.String: # [[ foo == */"*".py ]] or case *.py) ... esac if do_fnmatch and not part_val.do_split_glob: s = glob_.GlobEscape(part_val.s) elif do_ere and not part_val.do_split_glob: s = glob_.ExtendedRegexEscape(part_val.s) else: s = part_val.s else: if self.exec_opts.strict_array: # Examples: echo f > "$@"; local foo="$@" # TODO: This attributes too coarsely, to the word rather than the # parts. Problem: the word is a TREE of parts, but we only have a # flat list of part_vals. The only case where we really get arrays # is "$@", "${a[@]}", "${a[@]//pat/replace}", etc. e_die( "This word should evaluate to a string, but part of it was an " "array", word=word) # TODO: Maybe add detail like this. #e_die('RHS of assignment should only have strings. ' # 'To assign arrays, use b=( "${a[@]}" )') else: # It appears to not respect IFS s = ' '.join(s for s in part_val.strs if s is not None) strs.append(s) return value.Str(''.join(strs))
def _EvalWordFrame(self, frame, argv): all_empty = True all_split_glob = True any_split_glob = False #log('--- frame %s', frame) for s, do_split_glob in frame: #log('-- %r %r', s, do_split_glob) if s: all_empty = False if do_split_glob: any_split_glob = True else: all_split_glob = False # Elision of ${empty}${empty} but not $empty"$empty" or $empty"" if all_empty and all_split_glob: return # If every frag is quoted, e.g. "$a$b" or any part in "${a[@]}"x, then # don't do word splitting or globbing. if not any_split_glob: a = ''.join(s for s, _ in frame) argv.append(a) return will_glob = not self.exec_opts.noglob # Array of strings, some of which are BOTH IFS-escaped and GLOB escaped! frags = [] for frag, do_split_glob in frame: #log('frag %r do_split_glob %s', frag, do_split_glob) # If it was quoted, then if do_split_glob: # We're going to both split and glob. So we want to backslash # escape twice? # Suppose we get a literal \. # \ -> \\ # \\ -> \\\\ # Splitting takes \\\\ -> \\ # Globbing takes \\ to \ if it doesn't match if will_glob: frag = _BackslashEscape(frag) frag = _BackslashEscape(frag) else: if will_glob: frag = glob_.GlobEscape(frag) #log('GLOB ESCAPED %r', p2) frag = self.splitter.Escape(frag) #log('IFS ESCAPED %r', p2) frags.append(frag) flat = ''.join(frags) #log('flat: %r', flat) args = self.splitter.SplitForWordEval(flat) # space=' '; argv $space"". We have a quoted part, but we CANNOT elide. # Add it back and don't bother globbing. if not args and not all_split_glob: argv.append('') return #log('split args: %r', args) for a in args: # TODO: Expand() should take out parameter. results = self.globber.Expand(a) argv.extend(results)