Forcer un alias «ajouté» à chaque commande

11

Est-il possible d'ajouter de force un alias de synchronisation (faute d'un meilleur moyen de le formuler) à chaque commande bash?

Par exemple, j'aimerais avoir un utilisateur spécifique qui, chaque fois qu'une commande est exécutée, est toujours encapsulé avec dateavant et après, ou time.

Est-ce possible, et si oui comment?

garenne
la source
J'ai regardé avant et je n'ai pas trouvé de moyen de faire exactement cela. Comme le dit Caleb, vous pouvez l'utiliser preexec, mais vous ne voulez pas l'exécuter à l'intérieur de preexec(par exemple preexec() { time $1; }), car le shell l'exécute toujours après les preexecretours. Le mieux que nous puissions faire est donc quelque chose de similaire.
Mikel
@Mikel Je pense que vous pouvez utiliser la preexec()fonction pour envelopper ce qui était en cours d'exécution en récupérant la commande, en l'exécutant vous-même depuis l'intérieur de la fonction, puis en retournant une sorte d'erreur afin que le shell ne continue pas à exécuter la commande elle-même.
Caleb

Réponses:

10

Vous pouvez enregistrer l'heure à laquelle une ligne de commande démarre et l'heure à laquelle une invite s'affiche. Bash garde déjà une trace de la date de début de chaque ligne de commande dans son historique, et vous pouvez noter l'heure lorsque vous affichez l'invite suivante.

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"

Cela ne vous donne qu'une deuxième résolution, et seulement l'heure de l'horloge murale. Si vous souhaitez une meilleure résolution, vous devez utiliser une datecommande externe qui prend en charge le %Nformat des nanosecondes et le DEBUGpiège à appeler dateavant d'exécuter la commande à temps.

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

Même avec le DEBUGpiège, je ne pense pas qu'il existe un moyen d'afficher automatiquement les temps processeur pour chaque commande, ou d'être plus discriminant que d'invite à invite.


Si vous êtes prêt à utiliser un autre shell, voici comment obtenir un rapport de temps pour chaque commande dans zsh (cela ne se généralise pas à d'autres tâches):

REPORTTIME=0

Vous pouvez définir REPORTTIMEn'importe quelle valeur entière, les informations de synchronisation ne seront affichées que pour les commandes qui ont utilisé plus de ce nombre de secondes de temps processeur.

Zsh a pris cette fonctionnalité de csh où la variable est appelée time.

Gilles 'SO- arrête d'être méchant'
la source
3

Vos options ici vont dépendre de votre shell. En - zshil une fonction de crochet pratique appelée preexec()qui est exécuté juste avant que les commandes de shell interactives. En créant une fonction avec ce nom, vous pouvez provoquer l'exécution de choses. Vous pouvez également effectuer un suivi avec une fonction appelée precmd()qui s'exécutera juste avant que l'invite suivante ne soit dessinée, qui sera juste après la fin de votre commande.

En créant cette paire de fonctions, vous pouvez exécuter toutes les commandes arbitraires que vous souhaitez exécuter avant et après les commandes émises à l'invite. Vous pouvez l'utiliser pour enregistrer l'utilisation du shell, créer des verrous, tester l'environnement ou, comme dans votre exemple, calculer le temps ou les ressources dépensés pendant l'exécution d'une commande.

Dans cet exemple, nous allons créer nous-mêmes un horodatage de référence avant d'exécuter une commande à l'aide preexec()puis calculer le temps passé à exécuter la commande à l'aide precmd()et le sortir avant l'invite ou l'enregistrer. Exemple:

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

Remarque: Pour cet exemple particulier, il existe une fonction intégrée encore plus simple. Tout ce que vous avez à faire est d'activer les rapports d'exécution dans ZSH et il le fera automatiquement.

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

Dans une implémentation plus pratique de preexec(), je l'utilise pour voir si le shell s'exécute à l'intérieur tmuxou screen, si c'est le cas, pour envoyer des informations sur la commande en cours d'exécution en amont à afficher dans le nom de l'onglet.

Malheureusement en bash ce petit mécanisme n'existe pas. Voici la tentative d' un homme de le reproduire . Voir également la réponse de Gilles pour un petit hack astucieux similaire.

Caleb
la source
1
Et voici une version simplifiée de l'astuce precmd-through-DEBUG .
Gilles 'SO- arrête d'être méchant'
souhaite que cela soit disponible en bash!
warren
Voir les liens de Gilles et autres, il est implémentable en bash avec un peu de violon supplémentaire. Encore une fois, pourquoi ne lancez-vous pas simplement zsh? C'est une coquille à bascule avec plus de bonnes raisons de changer que ça!
Caleb
2
Si vous utilisez zsh, il existe un meilleur moyen de le faire. La variable d'environnement REPORTTIME, lorsqu'elle est définie, affichera les informations de temps d'exécution (comme si vous aviez exécuté la commande avec 'time' devant) pour toute commande prenant plus de $ REPORTTIME secondes. Il suffit de le mettre à 0 et il devrait vous indiquer l'heure de chaque commande, avec la répartition utilisateur / sys pour démarrer.
Joseph Garvin
1

Le moyen le plus simple serait probablement de définir PROMPT_COMMAND. Voir Variables Bash :

PROMPT_COMMAND
Si défini, la valeur est interprétée comme une commande à exécuter avant l'impression de chaque invite principale ( $PS1).

Par exemple, pour éviter d'écraser une commande d'invite existante, vous pouvez faire:

PROMPT_COMMAND="date ; ${PROMPT_COMMAND}"
cjm
la source
ne savait pas à ce sujet - ressemble à un bon début, @cjm
warren
1
C'est un début, mais ne résout pas le problème de savoir quand une commande a été exécutée. L'invite elle-même peut être affichée quelques minutes, heures ou jours avant qu'une commande ne soit tapée et exécutée.
Caleb
0

csh/ tcsha le meilleur support pour cette fonctionnalité (et l'a toujours eu).

  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.

En d'autres termes, set time=1affichera le temps consommé (système, utilisateur, écoulé) par toute commande qui a pris plus d'une seconde de temps processeur. Plain set timepermettra d'imprimer l'heure de toutes les commandes.

alexis
la source