def Echo(argv): """echo builtin. set -o sane-echo could do the following: - only one arg, no implicit joining. - no -e: should be echo c'one\ttwo\t' - no -n: should be write 'one' multiple args on a line: echo-lines one two three """ # NOTE: both getopt and optparse are unsuitable for 'echo' because: # - 'echo -c' should print '-c', not fail # - echo '---' should print ---, not fail arg, arg_index = ECHO_SPEC.ParseLikeEcho(argv) argv = argv[arg_index:] if arg.e: new_argv = [] for a in argv: parts = [] for id_, value in match.ECHO_LEXER.Tokens(a): p = word_compile.EvalCStringToken(id_, value) # Unusual behavior: '\c' prints what is there and aborts processing! if p is None: new_argv.append(''.join(parts)) for i, a in enumerate(new_argv): if i != 0: sys.stdout.write(' ') # arg separator sys.stdout.write(a) return 0 # EARLY RETURN parts.append(p) new_argv.append(''.join(parts)) # Replace it argv = new_argv #log('echo argv %s', argv) for i, a in enumerate(argv): if i != 0: sys.stdout.write(' ') # arg separator sys.stdout.write(a) if not arg.n: sys.stdout.write('\n') # Do I need the flush? Had a problem here under load, but it might not have # been because of that. # File "/home/andy/git/oil/bin/../core/cmd_exec.py", line 251, in _RunBuiltin # status = builtin.Echo(argv) # File "/home/andy/git/oil/bin/../core/builtin.py", line 431, in Echo # sys.stdout.flush() # IOError: [Errno 32] Broken pipe sys.stdout.flush() return 0
def _EvalWordPart(self, part, part_vals, quoted=False): """Evaluate a word part. Args: part_vals: Output parameter. Returns: None """ if part.tag == word_part_e.ArrayLiteralPart: raise AssertionError( 'Array literal should have been handled at word level') elif part.tag == word_part_e.LiteralPart: v = runtime.StringPartValue(part.token.val, not quoted) part_vals.append(v) elif part.tag == word_part_e.EscapedLiteralPart: val = part.token.val assert len(val) == 2, val # e.g. \* assert val[0] == '\\' s = val[1] v = runtime.StringPartValue(s, False) part_vals.append(v) elif part.tag == word_part_e.SingleQuotedPart: if part.left.id == Id.Left_SingleQuote: s = ''.join(t.val for t in part.tokens) elif part.left.id == Id.Left_DollarSingleQuote: # NOTE: This could be done at compile time s = ''.join( word_compile.EvalCStringToken(t.id, t.val) for t in part.tokens) else: raise AssertionError(part.left.id) v = runtime.StringPartValue(s, False) part_vals.append(v) elif part.tag == word_part_e.DoubleQuotedPart: self._EvalDoubleQuotedPart(part, part_vals) elif part.tag == word_part_e.CommandSubPart: id_ = part.left_token.id if id_ in (Id.Left_CommandSub, Id.Left_Backtick): v = self._EvalCommandSub(part.command_list, quoted) elif id_ in (Id.Left_ProcSubIn, Id.Left_ProcSubOut): v = self._EvalProcessSub(part.command_list, id_) else: raise AssertionError(id_) part_vals.append(v) elif part.tag == word_part_e.SimpleVarSub: maybe_decay_array = False # 1. Evaluate from (var_name, var_num, token) -> defined, value if part.token.id == Id.VSub_Name: var_name = part.token.val[1:] val = self.mem.GetVar(var_name) elif part.token.id == Id.VSub_Number: var_num = int(part.token.val[1:]) val = self._EvalVarNum(var_num) else: val, maybe_decay_array = self._EvalSpecialVar( part.token.id, quoted) #log('SIMPLE %s', part) val = self._EmptyStrOrError(val, token=part.token) if maybe_decay_array and val.tag == value_e.StrArray: val = self._DecayArray(val) v = _ValueToPartValue(val, quoted) part_vals.append(v) elif part.tag == word_part_e.BracedVarSub: self._EvalBracedVarSub(part, part_vals, quoted) elif part.tag == word_part_e.TildeSubPart: # We never parse a quoted string into a TildeSubPart. assert not quoted s = self._EvalTildeSub(part.token) v = runtime.StringPartValue(s, False) part_vals.append(v) elif part.tag == word_part_e.ArithSubPart: num = self.arith_ev.Eval(part.anode) v = runtime.StringPartValue(str(num), False) part_vals.append(v) elif part.tag == word_part_e.ExtGlobPart: # do_split_glob should be renamed 'unquoted'? or inverted and renamed # 'quoted'? part_vals.append(runtime.StringPartValue(part.op.val, True)) for i, w in enumerate(part.arms): if i != 0: part_vals.append(runtime.StringPartValue( '|', True)) # separator # This flattens the tree! self._EvalWordToParts(w, False, part_vals) # eval like not quoted? part_vals.append(runtime.StringPartValue(')', True)) # closing ) else: raise AssertionError(part.__class__.__name__)