Ich habe ein Setup-Skript für eine Vagrant-Box, mit der ich einzelne Schritte gemessen habe time
. Jetzt möchte ich die Zeitmessungen bedingt aktivieren oder deaktivieren.
Zuvor sah eine Zeile beispielsweise folgendermaßen aus:
time (apt-get update > /tmp/last.log 2>&1)
Jetzt dachte ich, ich könnte einfach so etwas machen:
MEASURE_TIME=true
[[ $MEASURE_TIME = true ]] && TIME="time --format=%e" || TIME=""
$TIME (apt-get update > /tmp/last.log 2>&1)
Aber das wird nicht funktionieren:
syntax error near unexpected token `apt-get'
`$TIME (apt-get update > /tmp/last.log 2>&1)'
Was ist das Problem hier?
Antworten:
Um eine Subshell zeitlich festlegen zu können, benötigen Sie das
time
Schlüsselwort und nicht den Befehl.Das
time
Schlüsselwort, ein Teil der Sprache, wird nur dann als solches erkannt, wenn es wörtlich und als erstes Wort eines Befehls eingegeben wird (und im Fall vonksh93
beginnt das nächste Token nicht mit a-
). Selbst die Eingabe"time"
funktioniert nicht, geschweige denn$TIME
(und wird stattdessen als Aufruf destime
Befehls verstanden).Sie können hier Aliase verwenden, die erweitert werden, bevor eine weitere Analyse durchgeführt wird (damit die Shell dieses
time
Schlüsselwort erkennt ):Das
time
Schlüsselwort akzeptiert keine Optionen (außer-p
inbash
), aber das Format kann mit derTIMEFORMAT
Variablen in festgelegt werdenbash
. (Dasshopt
Teil ist auchbash
-spezifisch, andere Muscheln brauchen das im Allgemeinen nicht).quelle
info -f bash --index-search=time
Während ein
alias
eine Möglichkeit , es zu tun ist, dies kann mit gemacht werdeneval
als auch - es ist nur , dass Sie nicht so viel wollen Sieeval
die Befehlsausführung , wie Sie mögeneval
den Befehl Erklärung .Ich mag
alias
es - ich benutze sie die ganze Zeit, aber ich mag Funktionen besser - insbesondere ihre Fähigkeit, mit Parametern umzugehen, und dass sie nicht unbedingt in der Befehlsposition erweitert werden müssen, wie es füralias
es erforderlich ist .Also dachte ich, vielleicht möchten Sie das auch versuchen:
Das
$IFS
bisschen geht hauptsächlich um$*
. Es ist wichtig , dass das( subshell bit )
ist auch das Ergebnis einer Shell - Erweiterung und so um die Argumente in einen parsable String I Gebrauch zu erweitern"$*"
(nichteval
"$@"
, nebenbei gesagt, es sei denn , Sie sind sie sicher alle der args auf Räume verbunden werden) . Das geteilte Trennzeichen zwischen args in"$*"
ist das erste Byte in$IFS
, und daher kann es gefährlich sein, fortzufahren, ohne seinen Wert sicherzustellen. So ist die Funktion speichert$IFS
, setzt er auf eine\n
lange genug ewline zuset ... "$*"
in"$3"
,unset
es s, dann wird ihr Wert setzt , wenn sie zuvor einen hatte.Hier ist eine kleine Demo:
Sie sehen, ich habe zwei Befehle in den Wert von
$TIME
dort eingefügt - jede Zahl ist in Ordnung - sogar keine -, aber stellen Sie sicher, dass sie maskiert und richtig zitiert wird - und dasselbe gilt für die Argumente dazu_time()
. Sie werden alle bei ihrer Ausführung zu einer einzigen Befehlszeichenfolge verkettet - aber jedes\n
Argument erhält seine eigene Ewline und kann daher relativ einfach verteilt werden. Oder Sie können sie alle in einem zusammenfassen, wenn Sie\n
möchten , und sie in Ewlines oder Semikolons oder was-haben-Sie trennen . Stellen Sie nur sicher, dass ein einzelnes Argument einen Befehl darstellt, den Sie beim Aufrufen in einem Skript in eine eigene Zeile einfügen möchten.\(
Zum Beispiel ist in Ordnung, solange es schließlich mit folgt\)
. Grundsätzlich das normale Zeug.Wenn
eval
das obige Snippet gefüttert wird, sieht es so aus:Und die Ergebnisse sehen aus wie ...
AUSGABE
Der
hash
Fehler zeigt an, dass ich keine/usr/bin/time
installiert habe (weil ich keine habe) undcommand
lässt uns wissen, welche Zeit läuft. Das Trailingset +x
ist ein weiterer Befehl, der nach ausgeführt wirdtime
(was möglich ist). Es ist wichtig, bei Eingabebefehlen vorsichtig zu sein, wenneval
Sie etwas eingeben .quelle
_time() { eval "$TIME $@"; }
? Die Verwendung einer Funktion hat den Nachteil, dass ein anderer Bereich für Variablen eingeführt wird (kein Problem für Unterschalen)"$@"
Erweiterung. Ich mag ein einziges Argument dazueval
- sonst wird es beängstigend. Ähm ... wie meinst du das mit dem unterschiedlichen Umfang? Ich dachte, dasfunction
eval
Verbindet seine Argumente vor der Ausführung, was Sie auf sehr verschlungene Weise versuchen. Ich meinte, das_time 'local var=1; blah'
würde dasvar
lokal machen_time
, oder das_time 'echo "$#"'
würde die$#
dieser_time
Funktion drucken , nicht die des Anrufers.eval
konzentriert seine Argumente auf Räume - was, wie Sie sagen, genau das ist, was ich hier mache - obwohl es keine ursprüngliche Absicht war. Ich werde das beheben.eval
Im"$*"
Gegensatz zu"$@"
ist eine Gewohnheit, die ich nach vielen Run-In's aufgegriffen habe,command not found
als Args an der falschen Stelle zusammengefügt wurden. Obwohl die Argumente letztendlich in der Funktion ausgeführt werden, ist es auf jeden Fall einfach genug, sie beim Aufruf zu erweitern, denke ich. Damit würde ich"$#"
sowieso machen.