Im Bash-Referenzhandbuch
Die Verwendung von time
als reserviertes Wort erlaubt das Timing von shell builtins , Shell-Funktionen und Pipelines . Eine externetime
Befehl kann diese nicht einfach timen.
-
Können Sie erklären, warum das Zitat das sagt?
Liegt das an dem Unterschied zwischen einem reservierten Wort und einem
Befehl, nicht nur beschränkt auf den Falltime
? Wie werden sie zum Beispiel von der Bash-Shell
analysiert oder anders interpretiert?Oder ist dies nur auf den Fall
time
beschränkt ? -
In den folgenden Beispielen
warum funktioniert die externe
time
Arbeit an einer eingebauten Shell und einer
Pipeline, während das Zitat sagt, dass es "diese nicht einfach timen kann"?Externe
time
auf einer eingebauten Shell :$ /usr/bin/time echo hello hello 0.00user 0.00system 0:00.00elapsed 0%CPU (0avgtext+0avgdata 1676maxresident)k 0inputs+0outputs (0major+78minor)pagefaults 0swaps
Externe
time
auf einer Pipeline :$ /usr/bin/time sleep 10 | sleep 5 0.00user 0.00system 0:10.00elapsed 0%CPU (0avgtext+0avgdata 1776maxresident)k 0inputs+0outputs (0major+79minor)pagefaults 0swaps
-
Warum funktioniert im folgenden Beispiel die externe
time
auf einer Shell
-Funktion scheitern? Was bedeutet seine Fehlerausgabe?$ function mytest () { sleep 10; } $ /usr/bin/time mytest /usr/bin/time: cannot run mytest: No such file or directory Command exited with non-zero status 127 0.00user 0.00system 0:00.03elapsed 0%CPU (0avgtext+0avgdata 1252maxresident)k 32inputs+0outputs (0major+30minor)pagefaults 0swaps
-
Anscheinend gilt das Zitat nicht nur für das Timing von Shell-Builtins,
Shell-Funktionen und Pipelines, sondern auch für das Timing einer Gruppe von
Befehlen :$ time { echo hello; sleep 3; echo tim; } hello tim real 0m3.002s user 0m0.000s sys 0m0.000s $ /usr/bin/time { echo hello; sleep 3; echo tim; } bash: syntax error near unexpected token `}'
Warum sagt die Shell „bash:Syntaxfehler nahe unerwartetem Token
}
” im Fall des Befehls/usr/bin/time
?
Akzeptierte Antwort:
In bash
, time
ist ein reserviertes Wort, also kann die Shell es auf eigene Weise parsen und Regeln dafür anwenden.
Hier ist der Code, der zeigt, wie bash
Parse-Zeile beginnt mit time
Reserviertes Wort:
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 */
}
Sehen Sie, time
kann von den meisten anderen bash
gefolgt werden reservierte Wörter.
Im Falle eines externen Befehls wurde die normale Regel angewendet, {
wurde als Eingabe von /usr/bin/time
betrachtet . }
allein ist ungültiges Token und bash
den Fehler melden.
In:
/usr/bin/time echo hello
externe time
hat das in die Shell eingebaute echo
nicht aufgerufen sondern das externe echo
Befehl.
Eine strace
bestätigt das:
$ 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 +++
....
Hier externe time
Suchen Sie Ihren PATH
Variable, um die ausführbare Befehlsdatei zu finden. Das erklärt auch, wenn Sie eine Funktion verwenden, erhalten Sie keine solche Datei oder kein solches Verzeichnis weil es keinen Befehl namens mytest
gibt in Ihrem PATH
.