Bir alt kabuğu şartlı olarak 'zaman' üzerinden nasıl geçirebilirim?


9

Tek adımları ölçmek için kullanılan bir Vagrant kutusu için bir kurulum komut dosyası var time. Şimdi zaman ölçümlerini koşullu olarak etkinleştirmek veya devre dışı bırakmak istiyorum.

Örneğin, daha önce bir satır şöyle görünecektir:

time (apt-get update > /tmp/last.log 2>&1)

Şimdi böyle bir şey yapabileceğimi düşündüm:

MEASURE_TIME=true
[[ $MEASURE_TIME = true ]] && TIME="time --format=%e" || TIME=""

$TIME (apt-get update > /tmp/last.log 2>&1)

Ancak bu işe yaramaz:

syntax error near unexpected token `apt-get'
`$TIME (apt-get update > /tmp/last.log 2>&1)'

Burada sorun ne?


3
Sadece akı kapasitörünün çalışması için hedef hıza ulaşmanız gerekir ;)
goldilocks

2
@goldilocks Mıknatıs mı demek istiyorsun? ;)
Aralık'ta

Yanıtlar:


13

Edebilmek zaman aşımına bir altkabuk, ihtiyacınız olan time anahtar kelimeyi değil, komut.

timeAnlamıyla girdiğinde anahtar kelime, dilin parçası, ancak böyle olarak tanınır ve bir komutun ilk sözcüğü olarak (ve durumunda ksh93, bir sonraki jeton ile başlamaz -). Girmek bile "time"tek başına çalışmaz $TIME(ve timebunun yerine komuta çağrı olarak kabul edilir ).

Burada, başka bir ayrıştırma turu gerçekleştirilmeden önce genişletilen diğer adları kullanabilirsiniz (böylece kabuğun bu timeanahtar kelimeyi tanımasına izin verir ):

shopt -s expand_aliases
alias time_or_not=
TIMEFORMAT=%E

MEASURE_TIME=true
[[ $MEASURE_TIME = true ]] && alias time_or_not=time

time_or_not (apt-get update > /tmp/last.log 2>&1)

time Anahtar kelime (haricinde seçenekleri almaz -piçinde bash), ancak biçim ile ayarlanabilir TIMEFORMATdeğişken bash. ( shoptbölüm de bash-özeldir, diğer mermiler genellikle buna ihtiyaç duymaz).


"Bir alt kabuğu zamanlayabilmek için, zaman anahtar kelimesine ihtiyacınız var" dediniz. Acaba bu davranış bazı yerlerde belgelendi?
cuonglm

@cuonglm, bkz.info -f bash --index-search=time
Stéphane Chazelas

3

Bir iken aliasbunu yapmak için bir yoldur, bu olabilir yapılabilir evalyanı - bu kadar çok istemiyorum bu sadece var evalistediğiniz kadar komut yürütme evalkomutu beyanı .

Ben aliases gibi - Ben her zaman onları kullanmak, ama daha iyi fonksiyonları severim - özellikle parametreleri işleme yetenekleri ve aliases için gerektiği gibi komut konumunda genişletilmesi gerekmez .

Bu yüzden belki de bunu denemek isteyeceğini düşündüm:

_time() if   set -- "${IFS+IFS=\$2;}" "$IFS" "$@" && IFS='
';      then set -- "$1" "$2" "$*"; unset IFS
             eval "$1 $TIME ${3#"$1"?"$2"?}"
        fi

$IFSBiraz esas olarak ilgili olduğu $*. O Bu çok önemli ( subshell bit )olduğunu da bir kabuk genişlemesi sonucu ve böylece bir ayrıştırılamaz dize ben kullanıma argümanları genişletmek için "$*" (yok eval "$@", bu arada, args ediyoruz belirli bütün alanlarda bağlı olarak birleştirilebilir sürece) . Arg'ler arasındaki bölünmüş sınırlayıcı "$*"ilk bayttır $IFSve bu nedenle değerini bilmeden ilerlemek tehlikeli olabilir. Fonksiyon kazandırır Yani $IFS, bir şekilde ayarlıyor \nyeterince uzun için ewline set ... "$*"içine "$3", unsetdaha önce bir tane olsaydı o zaman değerini sıfırlar böyle.

İşte küçük bir demo:

TIME='set -x; time'
_time \( 'echo "$(echo any number of subshells)"' \
         'command -V time'                        \
         'hash time'                              \
      \) 'set +x'

Gördüğünüz gibi $TIMEoraya iki komut koydum - herhangi bir sayı gayet iyi - hatta hiçbiri - ama kaçtığından ve doğru şekilde alıntılandığından emin olun - ve aynı şey argümanlar için de geçerli _time(). \nÇalıştırıldıklarında hepsi tek bir komut dizesine birleştirilecektir - ancak her arg kendi ewline'ını alır ve böylece nispeten kolayca yayılabilir. Ya da isterseniz hepsini bir araya \ntoplayabilir ve ewline veya noktalı virgül veya neye sahip olduğunuza ayırabilirsiniz. Tek bir argümanın, komut dosyası çağırdığınızda kendi satırına koymak için rahat hissettiğiniz bir komutu temsil ettiğinden emin olun. \(, örneğin, sonunda takip edildiği sürece iyidir \). Temelde normal şeyler.

Ne zaman evalyukarıdaki pasajı bunu beslenen alır gibi görünüyor:

+ eval 'IFS=$2;set -x; time (
echo "$(echo any number of subshells)"
command -V time
hash time
)
set +x'

Ve sonuçları ...

ÇIKTI

+++ echo any number of subshells
++ echo 'any number of subshells'
any number of subshells
++ command -V time
time is a shell keyword
++ hash time
bash: hash: time: not found

real    0m0.003s
user    0m0.000s
sys     0m0.000s
++ set +x

hashHata Ben yok olduğunu gösterir /usr/bin/timeyüklü (I do not çünkü) ve commandbizi çalıştığı zaman biliyorum yapalım. Sondaki sonrakiset +x bir komuttur (mümkün) - herhangi bir şey girerken giriş komutlarına dikkat etmek önemlidir . time eval


Yapmamak için bir sebep var _time() { eval "$TIME $@"; }mı? Bir fonksiyon kullanmanın, değişkenler için farklı bir kapsam sunma dezavantajı vardır (alt
kabuklar

@ StéphaneChazelas - "$@"genişlemedeki alıntılar nedeniyle . Tek bir argümanı seviyorum eval- aksi takdirde korkutucu oluyor. Hımm ... farklı kapsam hakkında ne demek istiyorsun? Ben sadece functionfonksiyonları olduğunu düşündüm ...
mikeserv

evalçok kıvrımlı bir şekilde yapmaya çalıştığınız şey yürütmeden önce argümanlarına katılır. Bu, _time 'local var=1; blah'bunu varyerel hale getirecek _timeya da bu işlevin, arayanın işlevini değil, _time 'echo "$#"'yazdıracağı anlamına geliyordu . $#_time
Stéphane Chazelas

@ StéphaneChazelas - Burada senin için iki sekme tamamladım. Sağ - evalboşluklara ilişkin argümanlarını - yani, tam olarak burada yaptığım şey - - inital niyet olmasa da - birleşiyor. Bunu tamir edeceğim. evaling "$*"aksine "$@"birçok sonra aldığım alışkanlıktır vadede-in yıllardan command not foundargs yanlış yerde katıldı zaman. Her halükarda, argümanlar sonuçta işlevde yürütülmesine rağmen, onları çağırmada genişletmek için yeterince basit, sanırım. Zaten ben de öyle yapardım "$#".
mikeserv

Yine de güzel bükülmüş hackery parçası için +1 ...
Stéphane Chazelas
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.