Mam skrypt instalacyjny dla pudełka Vagrant, w którym mierzyłem pojedyncze kroki time
. Teraz chciałbym warunkowo włączyć lub wyłączyć pomiary czasu.
Na przykład wcześniej linia wyglądałaby tak:
time (apt-get update > /tmp/last.log 2>&1)
Teraz pomyślałem, że mogę po prostu zrobić coś takiego:
MEASURE_TIME=true
[[ $MEASURE_TIME = true ]] && TIME="time --format=%e" || TIME=""
$TIME (apt-get update > /tmp/last.log 2>&1)
Ale to nie zadziała:
syntax error near unexpected token `apt-get'
`$TIME (apt-get update > /tmp/last.log 2>&1)'
W czym problem?
Odpowiedzi:
Aby móc określić czas podpowłoki, potrzebujesz
time
słowa kluczowego , a nie polecenia.time
Słów kluczowych, częścią języka, jest uznawane tylko jako takie, gdy wszedł dosłownie i jako pierwsze słowo polecenia (aw przypadkuksh93
, a następny znak nie startuje z-
). Nawet wejście"time"
nie zadziała, nie mówiąc już o tym$TIME
(atime
zamiast tego zostanie odebrane jako wywołanie polecenia).Możesz użyć tutaj aliasów, które są rozwinięte przed wykonaniem kolejnej rundy analizowania (aby powłoka rozpoznała to
time
słowo kluczowe):Słowo
time
kluczowe nie przyjmuje opcji (z wyjątkiem-p
inbash
), ale format można ustawić za pomocąTIMEFORMAT
zmiennej inbash
. (shopt
część jest równieżbash
specyficzna, inne powłoki na ogół tego nie potrzebują).źródło
info -f bash --index-search=time
Chociaż jest
alias
to jeden ze sposobów, można to zrobićeval
również za pomocą - po prostu nie tyle chceszeval
wykonania polecenia, ile chceszeval
deklaracji polecenia .podoba mi się
alias
es - używam ich cały czas, ale bardziej lubię funkcje - szczególnie ich zdolność do obsługi parametrów i że niekoniecznie muszą być one rozszerzane w pozycji poleceń, jak jest to wymagane dlaalias
es.Pomyślałem więc, że może też chcesz spróbować:
Chodzi
$IFS
głównie o to$*
. Ważne jest, aby wynik( subshell bit )
był również wynikiem rozszerzenia powłoki, a więc w celu rozwinięcia argumentów w parsowalny ciąg, którego używam"$*"
(nieeval
"$@"
, nawiasem mówiąc, chyba że jesteś pewien, że wszystkie argumenty można połączyć spacjami) . Rozdzielony separator między argumentami"$*"
jest pierwszym bajtem wejściowym$IFS
, więc kontynuowanie pracy bez pewności co do jej wartości może być niebezpieczne. Tak więc funkcja zapisuje$IFS
, ustawia ją na\n
ewline wystarczająco długo, abyset ... "$*"
w"$3"
,unset
s, a następnie resetuje swoją wartość, jeśli wcześniej miała taką.Oto małe demo:
Widzisz, umieściłem w poleceniu dwie wartości
$TIME
- dowolna liczba jest w porządku - nawet żadna - ale upewnij się, że została poprawnie zmieniona i zacytowana - i to samo dotyczy argumentów_time()
. Wszystkie zostaną połączone w jeden ciąg komend, gdy zostaną wykonane - ale każdy argument otrzymuje własny\n
ewline, dzięki czemu można je stosunkowo łatwo rozłożyć. W przeciwnym razie możesz zebrać je wszystkie w jednym, jeśli chcesz, i rozdzielić je na\n
ewline lub średniki lub co tam masz. Po prostu upewnij się, że pojedynczy argument reprezentuje polecenie, które możesz swobodnie umieścić w swoim wierszu w skrypcie podczas jego wywoływania.\(
, na przykład jest w porządku, o ile w końcu zostanie zastosowane\)
. Zasadniczo normalne rzeczy.Po
eval
otrzymaniu powyższego fragmentu wygląda on następująco:A jego wyniki wyglądają jak ...
WYNIK
hash
Błąd wskazuje, że nie masz/usr/bin/time
zainstalowanego (bo nie) icommand
niech nas nie wie czym jest uruchomiony. Trailingset +x
jest kolejną komendą wykonywaną potime
(co jest możliwe) - ważne jest, aby zachować ostrożność przy komendach wejściowych podczaseval
pisania czegokolwiek.źródło
_time() { eval "$TIME $@"; }
? Korzystanie z funkcji ma tę wadę, że wprowadza inny zakres dla zmiennych (nie jest to problem dla podpowłoki)"$@"
rozszerzeniu. Lubię jednego argumentueval
- w przeciwnym razie robi się strasznie. Ummm .... co masz na myśli mówiąc o innym zakresie? Myślałem, że to tylkofunction
funkcje ...eval
dołącza do argumentów przed wykonaniem, co próbujesz zrobić w bardzo zawiły sposób. Miałem na myśli,_time 'local var=1; blah'
że uczyni tovar
lokalnym lokalnym_time
lub_time 'echo "$#"'
wydrukuje$#
tę_time
funkcję, a nie wywołującego.eval
konkluduje swoje argumenty na przestrzeniach - co, jak mówisz, jest dokładnie tym, co tutaj robię - chociaż nie było to początkowe zamierzenie. Naprawię to.eval
ing"$*"
w przeciwieństwie do"$@"
to nawyk Podniosłam po wielu run-in jest zecommand not found
kiedy args zostały połączone w niewłaściwym miejscu. W każdym razie, chociaż argumenty są ostatecznie wykonywane w funkcji, myślę, że wystarczy je rozwinąć przy wywołaniu. Tak czy"$#"
inaczej bym zrobił .