Memaksa alias 'ditambahkan' ke setiap perintah

11

Apakah mungkin untuk menambahkan alias waktu secara paksa (karena tidak ada cara yang lebih baik untuk mengungkapkannya) ke setiap perintah di bash?

Sebagai contoh, saya ingin memiliki pengguna tertentu yang setiap kali perintah dijalankan, selalu dibungkus dengan datesebelum dan sesudah, atau time.

Apakah ini mungkin dan jika iya, bagaimana?

warren
sumber
Saya melihat sebelumnya, dan tidak dapat menemukan cara untuk melakukan ini. Seperti kata Caleb, Anda dapat menggunakan preexec, tetapi Anda tidak ingin menjalankannya di dalam preexec(misalnya preexec() { time $1; }), karena shell masih menjalankannya setelah preexeckembali. Jadi yang terbaik yang bisa kita lakukan adalah sesuatu yang serupa.
Mikel
@Mikel Saya pikir Anda bisa menggunakan preexec()fungsi untuk benar-benar membungkus apa pun yang sedang dieksekusi dengan mengambil perintah, menjalankannya sendiri dari dalam fungsi, lalu mengembalikan beberapa jenis kesalahan sehingga shell tidak melanjutkan untuk mengeksekusi perintah itu sendiri.
Caleb

Jawaban:

10

Anda dapat merekam waktu baris perintah dimulai dan waktu prompt ditampilkan. Bash sudah melacak tanggal mulai setiap baris perintah dalam riwayatnya, dan Anda dapat mencatat waktu ketika Anda menampilkan prompt berikutnya.

print_command_wall_clock_time () {
  echo Wall clock time: \
    $(($(date +%s) - $(HISTTIMEFORMAT="%s ";
                       set -o noglob;
                       set $(history 1); echo $2)))
}
PROMPT_COMMAND=print_command_wall_clock_time$'\n'"$PROMPT_COMMAND"

Ini hanya memberi Anda resolusi kedua, dan hanya waktu jam dinding. Jika Anda menginginkan resolusi yang lebih baik, Anda perlu menggunakan dateperintah eksternal yang mendukung %Nformat untuk nanodetik, dan DEBUGperangkap untuk memanggil datesebelum menjalankan perintah ke waktu.

call_date_before_command () {
  date_before=$(date +%s.%N)
}
print_wall_clock_time () {
  echo Wall clock time: \
    $((date +"$date_before - %s.%N" | bc))
}
trap call_date_before_command DEBUG
PROMPT_COMMAND=print_command_wall_clock_time

Bahkan dengan DEBUGjebakan, saya tidak berpikir ada cara untuk secara otomatis menampilkan waktu prosesor untuk setiap perintah, atau menjadi lebih diskriminatif daripada cepat ke cepat.


Jika Anda ingin menggunakan shell yang berbeda, inilah cara mendapatkan laporan waktu untuk setiap perintah di zsh (ini tidak menggeneralisasi ke tugas lain):

REPORTTIME=0

Anda dapat mengatur REPORTTIMEke nilai integer apa pun, informasi pewaktuan hanya akan ditampilkan untuk perintah yang menggunakan lebih dari beberapa detik waktu prosesor ini.

Zsh mengambil fitur ini dari csh tempat variabel dipanggil time.

Gilles 'SANGAT berhenti menjadi jahat'
sumber
3

Pilihan Anda di sini akan tergantung pada shell Anda. Di zshsana disebut fungsi hook yang nyaman preexec()yang dijalankan tepat sebelum perintah shell interaktif. Dengan membuat fungsi dengan nama ini, Anda dapat menyebabkan sesuatu dieksekusi. Anda juga dapat menindaklanjuti dengan fungsi yang disebut precmd()yang akan berjalan tepat sebelum prompt berikutnya dibuat, yang akan segera setelah perintah Anda selesai.

Dengan membuat pasangan fungsi ini, Anda dapat memiliki perintah sewenang-wenang apa pun yang ingin Anda jalankan sebelum dan sesudah perintah apa pun yang dikeluarkan saat diminta. Anda bisa menggunakan ini untuk mencatat penggunaan shell, membuat kunci, menguji lingkungan, atau seperti dalam contoh Anda menghitung waktu atau sumber daya yang dihabiskan saat perintah dijalankan.

Dalam contoh ini, kita akan membuat timestamp tolok ukur sendiri sebelum menjalankan perintah menggunakan preexec()lalu menghitung waktu yang dihabiskan untuk mengeksekusi perintah menggunakan precmd()dan menampilkannya sebelum prompt atau menghapusnya. Contoh:

preexec() {
   CMDSTART=$(date +%s%N)
}
precmd() {
   CMDRUNTIME=$(($(date +%s%N)-$CMDSTART))
   echo "Last command ran for $CMDRUNTIME nanoseconds."
}

Catatan: Untuk contoh khusus ini, ada fungsi builtin yang bahkan lebih mudah. Yang harus Anda lakukan adalah mengaktifkan pelaporan runtime di ZSH dan itu akan melakukan ini secara otomatis.

$ export REPORTTIME=0
$ ls -d
./
ls -BF --color=auto -d  0.00s user 0.00s system 0% cpu 0.002 total

Dalam implementasi yang lebih praktis preexec(), saya menggunakannya melihat apakah shell berjalan di dalam tmuxatau screendan, jika demikian, untuk mengirim informasi tentang perintah yang sedang berjalan di hulu untuk ditampilkan dalam nama tab.

Sayangnya di bash, mekanisme kecil ini tidak ada. Ini adalah upaya seorang pria untuk meniru itu . Lihat juga jawaban Gilles untuk hack kecil yang serupa.

Caleb
sumber
1
Dan ini adalah versi sederhana dari trik precmd-through-DEBUG .
Gilles 'SO- berhenti bersikap jahat'
berharap ini tersedia di bash!
warren
Lihat tautan Gilles dan yang lainnya, ini dapat diterapkan di bash dengan sedikit mengutak-atik. Sekali lagi, mengapa Anda tidak menjalankan zsh saja? Ini adalah goyang shell dengan alasan yang lebih baik untuk beralih dari ini!
Caleb
2
Jika Anda menggunakan zsh, ada cara yang lebih baik untuk melakukannya. Variabel lingkungan REPORTTIME ketika diatur akan menampilkan informasi waktu eksekusi (seolah-olah Anda telah menjalankan perintah dengan 'waktu' di depannya) untuk perintah apa pun yang membutuhkan waktu lebih dari $ REPORTTIME detik. Cukup atur ke 0 dan itu akan memberi tahu Anda waktu untuk setiap perintah, dengan rincian pengguna / sistem untuk boot.
Joseph Garvin
1

Cara termudah mungkin akan ditetapkan PROMPT_COMMAND. Lihat Variabel Bash :

PROMPT_COMMAND
Jika diatur, nilai ditafsirkan sebagai perintah untuk dijalankan sebelum pencetakan setiap prompt utama ( $PS1).

Misalnya, untuk menghindari menimpa perintah prompt yang ada, Anda dapat melakukan:

PROMPT_COMMAND="date ; ${PROMPT_COMMAND}"
cjm
sumber
tidak tahu tentang yang itu - sepertinya awal yang baik, @cjm
warren
1
Ini awal, tetapi tidak membahas masalah mengetahui kapan perintah dijalankan. Prompt itu sendiri mungkin diambil beberapa menit atau beberapa jam atau beberapa hari sebelum sebuah perintah diketik dan dijalankan.
Caleb
0

cshSaya tcshmemiliki dukungan terbaik untuk fitur ini (dan selalu memilikinya).

  The `time` shell variable can be set to execute the time builtin  command
  after the completion of any process that takes more than a given number
  of CPU seconds.

Dengan kata lain, set time=1akan mencetak waktu yang digunakan (sistem, pengguna, berlalu) dengan perintah apa pun yang membutuhkan lebih dari 1 detik waktu cpu. Plain set timeakan memungkinkan pencetakan waktu untuk semua perintah.

Alexis
sumber