The "non-printing escape sequence" is needed when using non-printing characters in $PS1 because bash needs to know the position of the cursor so that the screen can be updated correctly when you edit the command line. Bash does that by counting the number of characters in the $PS1 prompt and then that's the column number the cursor is in.
However, if you place non-printing sequences in $PS1, then that count is wrong and the line can be messed up if you edit the command line. Hence the introduction of the \[
and \]
markers to indicate that the enclosed bytes should not be counted.
In bash
, time
is a reserved word, so the shell can parse it the own way and apply rules for it.
Here is the code show how bash
parse line start with time
reserved word:
static int
time_command_acceptable ()
{
#if defined (COMMAND_TIMING)
int i;
if (posixly_correct && shell_compatibility_level > 41)
{
/* Quick check of the rest of the line to find the next token. If it
begins with a `-', Posix says to not return `time' as the token.
This was interp 267. */
i = shell_input_line_index;
while (i < shell_input_line_len && (shell_input_line[i] == ' ' || shell_input_line[i] == '\t'))
i++;
if (shell_input_line[i] == '-')
return 0;
}
switch (last_read_token)
{
case 0:
case ';':
case '\n':
case AND_AND:
case OR_OR:
case '&':
case WHILE:
case DO:
case UNTIL:
case IF:
case THEN:
case ELIF:
case ELSE:
case '{': /* } */
case '(': /* )( */
case ')': /* only valid in case statement */
case BANG: /* ! time pipeline */
case TIME: /* time time pipeline */
case TIMEOPT: /* time -p time pipeline */
case TIMEIGN: /* time -p -- ... */
return 1;
default:
return 0;
}
#else
return 0;
#endif /* COMMAND_TIMING */
}
You see, time
can be followed by most others bash
reserved words.
In case of external command, the normal rule was applied, {
was considered input of /usr/bin/time
. }
alone is invalid token, and bash
raise the error.
In:
/usr/bin/time echo hello
external time
did not call the shell builtin echo
but the external echo
command.
A strace
verifies that:
$ strace -fe execve /usr/bin/time echo 1
execve("/usr/bin/time", ["/usr/bin/time", "echo", "1"], [/* 64 vars */]) = 0
Process 25161 attached
....
[pid 25161] execve("/usr/bin/echo", ["echo", "1"], [/* 64 vars */]) = -1 ENOENT (No such file or directory)
[pid 25161] execve("/bin/echo", ["echo", "1"], [/* 64 vars */]) = 0
1
[pid 25161] +++ exited with 0 +++
....
Here external time
lookup your PATH
variable to find the command executable. That also explain in case of using a function, you got No such file or directory becasue there's no command named mytest
in your PATH
.
Best Answer
It is essentially a generic syntax error, not specifically related to the
ls
token.bash
uses a yacc parser, which calls a commonyyerror()
on any problem, Within the resulting error-handling, it proceeds to try to pinpoint the error. The message is coming from this chunk (see source):In other words, it's already confused by the
'('
, and having looked-ahead for context is reporting thels
.A
(
would be legal at the beginning of a command, but not embedded. Per manual page:Further reading: