Permalink
Browse files

Implement echo -e '\c'.

This is an unusual feature which not only truncates the current string,
but stops later arguments from being printed.

dash, bash, and zsh all implement it.
  • Loading branch information...
Andy Chu
Andy Chu committed Dec 26, 2017
1 parent 9c8814d commit e193478fe5498d87c6ffc3910abd2edbe81c2e17
Showing with 35 additions and 10 deletions.
  1. +28 −9 core/builtin.py
  2. +1 −1 core/id_kind.py
  3. +6 −0 spec/builtin-io.test.sh
View
@@ -229,6 +229,7 @@ def Resolve(argv0):
ECHO_LEXER = lexer.SimpleLexer([
R(r'\\[0abeEfrtnv]', Id.Char_OneChar),
C(r'\c', Id.Char_Stop),
# Note: tokens above \0377 can either be truncated or be flagged a syntax
# error in strict mode.
@@ -276,6 +277,9 @@ def _EvalStringPart(id_, value):
c = value[1]
return _ONE_CHAR[c]
elif id_ == Id.Char_Stop: # \c returns a special sentinel
return None
elif id_ == Id.Char_Octal:
# TODO: Error checking for \0777
s = value[2:]
@@ -315,34 +319,49 @@ def _EvalStringPart(id_, value):
def Echo(argv):
"""
echo builtin. Doesn't depend on executor state.
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'
TODO: Where to put help? docstring?
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, i = echo_spec.ParseLikeEcho(argv)
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 ECHO_LEXER.Tokens(a):
p = _EvalStringPart(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)
n = len(argv)
for i in xrange(i, n-1):
sys.stdout.write(argv[i])
sys.stdout.write(' ') # arg separator
if argv:
sys.stdout.write(argv[-1])
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')
View
@@ -399,7 +399,7 @@ def _AddKinds(spec):
# For C-escaped strings.
spec.AddKind('Char', [
'OneChar', 'Hex', 'Octal', 'Unicode4', 'Unicode8', 'Literals'
'OneChar', 'Stop', 'Hex', 'Octal', 'Unicode4', 'Unicode8', 'Literals'
])
View
@@ -43,6 +43,12 @@ echo -e 'ab\0cd'
# dash truncates it
# BUG dash stdout-json: "-e ab\n"
### \c stops processing input
echo -e xy 'ab\cde' 'ab\cde'
# stdout-json: "xy ab"
# OK dash stdout-json: "-e xy ab"
# N-I mksh stdout-json: "xy abde abde"
### echo -e with hex escape
echo -e 'abcd\x65f'
# stdout-json: "abcdef\n"

0 comments on commit e193478

Please sign in to comment.