Saya memiliki skrip pengaturan untuk kotak Vagrant tempat saya biasa mengukur langkah tunggal time
. Sekarang saya ingin mengaktifkan atau menonaktifkan pengukuran waktu secara kondisional.
Misalnya, sebelumnya sebuah garis akan terlihat seperti:
time (apt-get update > /tmp/last.log 2>&1)
Sekarang saya pikir saya bisa melakukan sesuatu seperti ini:
MEASURE_TIME=true
[[ $MEASURE_TIME = true ]] && TIME="time --format=%e" || TIME=""
$TIME (apt-get update > /tmp/last.log 2>&1)
Tetapi ini tidak akan berhasil:
syntax error near unexpected token `apt-get'
`$TIME (apt-get update > /tmp/last.log 2>&1)'
Apa masalahnya di sini?
Jawaban:
Untuk dapat menghitung waktu subkulit, Anda perlu
time
kata kunci , bukan perintah.Kata
time
kunci, bagian dari bahasa, hanya dikenali seperti itu ketika dimasukkan secara harfiah dan sebagai kata pertama dari suatu perintah (dan dalam kasusksh93
, maka token berikutnya tidak dimulai dengan a-
). Bahkan masuk"time"
tidak akan berhasil apalagi$TIME
(dan akan dianggap sebagai panggilan untuktime
perintah).Anda dapat menggunakan alias di sini yang diperluas sebelum putaran parsing dilakukan (jadi biarkan shell mengenali
time
kata kunci itu):Kata
time
kunci tidak mengambil opsi (kecuali untuk-p
dalambash
), tetapi format dapat diatur denganTIMEFORMAT
variabel dalambash
. (shopt
bagian ini jugabash
khusus, shell lain umumnya tidak membutuhkan itu).sumber
info -f bash --index-search=time
Sementara an
alias
adalah salah satu cara untuk melakukannya, ini dapat dilakukan denganeval
juga - hanya saja Anda tidak begitu ingineval
eksekusi perintah seperti yang Anda inginkaneval
pada deklarasi perintah .Saya suka
alias
es - saya menggunakan mereka sepanjang waktu, tapi saya suka fungsi lebih baik - terutama kemampuan mereka untuk menangani parameter dan bahwa mereka tidak perlu diperluas dalam posisi perintah seperti yang diperlukan untukalias
es.Jadi saya pikir mungkin Anda ingin mencoba ini juga:
The
$IFS
bit terutama tentang$*
. Sangat penting bahwa( subshell bit )
ini juga merupakan hasil dari ekspansi shell dan jadi untuk memperluas argumen menjadi string yang dapat diuraikan yang saya gunakan"$*"
(janganeval
"$@"
, omong-omong, kecuali jika Anda yakin semua argumen dapat digabungkan pada spasi) . Pemisah pemisah antara args in"$*"
adalah byte pertama$IFS
, dan karenanya bisa berbahaya untuk melanjutkan tanpa memastikan nilainya. Jadi fungsinya menyimpan$IFS
, menetapkannya ke\n
baris baru cukup lamaset ... "$*"
menjadi"$3"
,unset
s itu, lalu mengatur ulang nilainya jika sebelumnya memiliki satu.Ini sedikit demo:
Anda lihat saya meletakkan dua perintah di nilai
$TIME
sana - nomor berapa pun baik - bahkan tidak ada - tapi pastikan itu lolos dan dikutip dengan benar - dan hal yang sama berlaku untuk argumen_time()
. Mereka semua akan digabungkan menjadi string perintah tunggal ketika dieksekusi - tetapi masing-masing arg mendapatkan\n
ewline sendiri dan sehingga mereka dapat disebarkan dengan relatif mudah. Atau Anda bisa mengelompokkannya menjadi satu, jika mau, dan memisahkannya di\n
ewline atau semi-titik dua atau apa pun yang Anda miliki. Pastikan saja satu argumen mewakili perintah yang akan membuat Anda merasa nyaman untuk meletakkan barisnya sendiri dalam sebuah skrip ketika Anda menyebutnya.\(
, misalnya baik-baik saja, asalkan pada akhirnya diikuti dengan\)
. Pada dasarnya hal-hal normal.Ketika
eval
mendapat potongan di atas, sepertinya:Dan, hasilnya terlihat seperti ...
KELUARAN
The
hash
kesalahan menunjukkan bahwa saya tidak memiliki/usr/bin/time
diinstal (karena saya tidak) dancommand
mari kita tahu mana waktu berjalan. Trailingset +x
adalah perintah lain yang dieksekusi setelahtime
(yang mungkin) - penting untuk berhati-hati dengan perintah input saat memasukkaneval
apa pun.sumber
_time() { eval "$TIME $@"; }
? Menggunakan fungsi memiliki kelemahan dalam memperkenalkan ruang lingkup yang berbeda untuk variabel (bukan masalah untuk subkulit)"$@"
ekspansi. Saya suka satu arg untukeval
- itu menakutkan kalau tidak. Ummm .... bagaimana maksudmu tentang ruang lingkup yang berbeda? Saya pikir itu hanyafunction
berfungsi ...eval
bergabung dengan argumennya sebelum mengeksekusi yang merupakan apa yang Anda coba lakukan dengan cara yang sangat berbelit-belit. Aku berarti bahwa_time 'local var=1; blah'
akan membuatvar
lokal untuk itu_time
, atau bahwa_time 'echo "$#"'
akan mencetak$#
itu_time
fungsi, tidak pemanggil.eval
menyuarakan argumennya pada spasi - yang, seperti yang Anda katakan, persis apa yang saya lakukan di sini - meskipun itu bukan niat awal. Saya akan memperbaikinya.eval
Yang"$*"
bertentangan"$@"
adalah kebiasaan yang saya ambil setelah banyakcommand not found
pertengkaran dengan ketika args bergabung di tempat yang salah. Bagaimanapun, meskipun argumen akhirnya dieksekusi dalam fungsi, itu cukup sederhana untuk memperluas mereka pada doa, saya pikir. Lagipula itu yang akan saya lakukan"$#"
.