dire si la dernière commande était vide dans PROMPT_COMMAND

12

En bash, depuis l'intérieur de PROMPT_COMMAND, existe-t-il un moyen de savoir si l'utilisateur vient d'appuyer sur 'return' et n'a pas entré de commande?

utilisateur
la source

Réponses:

7

Vérifiez si le numéro d'historique a été incrémenté. Une invite annulée ou une invite où l'utilisateur vient d'appuyer Entern'augmentera pas le numéro d'historique.

Le numéro d'historique est disponible dans la variable HISTCMD, mais il n'est pas disponible dans PROMPT_COMMAND(car ce que vous voulez, c'est en fait le numéro d'historique de la commande précédente; la commande qui s'exécute PROMPT_COMMANDelle-même n'a pas de numéro d'historique). Vous pouvez obtenir le nombre à partir de la sortie de fc.

prompt_command () {
  HISTCMD_previous=$(fc -l -1); HISTCMD_previous=${HISTCMD_previous%%$'[\t ]'*}
  if [[ -z $HISTCMD_before_last ]]; then
    # initial prompt
  elif [[ $HISTCMD_before_last = "$HISTCMD_previous" ]]; then
    # cancelled prompt
  else
    # a command was run
  fi
  HISTCMD_before_last=$HISTCMD_previous
}
PROMPT_COMMAND='prompt_command'

Notez que si vous avez activé l'écrasement des doublons dans l'historique ( HISTCONTROL=ignoredupsou HISTCONTROL=erasedups), cela signalera par erreur une commande vide après avoir exécuté deux commandes identiques successivement.

Gilles 'SO- arrête d'être méchant'
la source
Merci, Gilles. Il me manque quelque chose ici. Cela ne semble jamais fonctionner, car mettre 'echo hello' sur la première ligne de la fonction littérale ne fonctionne pas, bien que PROMPT_COMMAND = 'echo hello' le fasse. Je pensais que c'était peut-être le problème HISTCMD_previous vs HISTCMD_PREVIOUS, mais pas de dés. Je continuerai à pousser, mais je commente car votre bash fu est clairement à des lieues au-delà du mien.
utilisateur
@user J'ai corrigé plus de fautes de frappe, en particulier le ${HISTCMD_previous%%$'[\t ]'*}bit manquait le $'…'et `, j'ai fini par tronquer après t` ou espace au lieu de après tab ou espace, mais bash imprime un onglet.
Gilles 'SO- arrête d'être méchant'
1
Cette solution est basée sur l'hypothèse que les doublons sont enregistrés dans l'historique (ce qui est désactivé pour moi). Par conséquent, cette solution ne fonctionne pas comme prévu pour les commandes répétées alors que les doublons ne sont pas enregistrés dans l'historique.
schlimmchen
4

Il existe une solution de contournement, mais elle a certaines exigences:

Vous devez définir $HISTCONTROLpour enregistrer TOUTES les commandes, ainsi que les doublons et les espaces. Alors définissez:

HISTCONTROL=

Définissez maintenant une fonction à appeler $PROMPT_COMMAND:

isnewline () {
  # read the last history number
  prompt_command__isnewline__last="$prompt_command__isnewline__curr"
  # get the current history number
  prompt_command__isnewline__curr="$(history 1 | grep -oP '^\ +\K[0-9]+')"
  [ "$prompt_command__isnewline__curr" = "$prompt_command__isnewline__last" ] && \
    echo "User hit return"
}

Maintenant, définissez la $PROMPT_COMMANDvariable:

PROMPT_COMMAND="isnewline"

Voir la sortie:

user@host:~$ true
user@host:~$ <return>
User hit return
user@host:~$ <space><return>
user@host:~$ 
le chaos
la source
Je ne comprends pas pourquoi vous utilisez un fichier temporaire ici. La variable lastest conservée d'une invocation de isnewlineà la suivante (choisissez seulement un nom moins générique comme prompt_command__isnewline__lastpour éviter les conflits).
Gilles 'SO- arrête d'être méchant'
@Gilles Vous avez raison, je l'ai changé, merci pour votre suggestion
chaos
Merci, chaos. J'ai utilisé la même idée pour ce qui suit, qui est un peu plus facile à analyser. HISTCONTROL="" function last_was_blank { local last_command="$(history 1)" if [[ "$last_was_blank_PREVIOUS_LINE" = "$last_command" ]] ; then echo "true" else echo "false" fi export last_was_blank_PREVIOUS_LINE="$last_command" } PROMPT_COMMAND=last_was_blank
utilisateur
1

Je ne connais aucun moyen de le faire, en soi . Mais vous pouvez obtenir le même effet en utilisant

piège le débogage de some_command_or_function

Cela entraînera l' some_command_or_functionappel à chaque fois que vous exécutez une commande. La chose délicate est qu'elle ne sera pas appelée si vous appuyez simplement sur Enter- sauf si vous avez défini un PROMPT_COMMAND, auquel cas frapper Enterinvoque le PROMPT_COMMAND, qui, à son tour, déclenche le piège.

La façon la plus simple d'obtenir le résultat souhaité est peut-être de définir une fonction d'interruption de débogage au lieu d'utiliser un PROMPT_COMMAND. Mais je ne peux pas le dire, car je ne sais pas quel résultat tu veux. Si vous voulez que quelque chose se produise lorsque vous venez de frapper Enteret que quelque chose de différent / supplémentaire se produise lorsque vous tapez une commande, alors (AFAIK) vous devez utiliser une interruption de débogage et une PROMPT_COMMAND. Voir cette réponse et  celle-ci pour un moyen de faire en sorte que les deux mécanismes fonctionnent bien ensemble.

Scott
la source
0

(Cela aurait été un commentaire à la réponse acceptée si j'avais été autorisé à ajouter des commentaires ...) @schlimmen, vous pouvez définir HISTTIMEFORMATquelque chose comme HISTTIMEFORMAT='%F %T ', puis enregistrer et comparer history 1. C'est parce qu'avec les effacements, au moins l'horodatage de la dernière commande (éventuellement répétée) change à chaque fois --- et avec HISSTIMEFORMATun réglage approprié, history 1affichera l'horodatage (contrairement fc), et différera donc même entre les commandes répétées.

Pavel Smerk
la source