Je voudrais implémenter une fonction dans Bash qui augmente (et renvoie) un nombre à chaque appel. Malheureusement, cela semble non trivial puisque j'appelle la fonction à l'intérieur d'un sous-shell et qu'il ne peut par conséquent pas modifier les variables de son shell parent.
Voici ma tentative:
PS_COUNT=0
ps_count_inc() {
let PS_COUNT=PS_COUNT+1
echo $PS_COUNT
}
ps_count_reset() {
let PS_COUNT=0
}
Cela serait utilisé comme suit (et donc mon besoin d'appeler les fonctions à partir d'un sous-shell):
PS1='$(ps_count_reset)> '
PS2='$(ps_count_inc) '
De cette façon, j'aurais une invite multi-lignes numérotée:
> echo 'this
1 is
2 a
3 test'
Mignonne. Mais en raison de la limitation mentionnée ci-dessus ne fonctionne pas.
Une solution qui ne fonctionnerait pas serait d'écrire le nombre dans un fichier au lieu d'une variable. Cependant, cela créerait un conflit entre plusieurs sessions s'exécutant simultanément. Je pourrais bien sûr ajouter l'ID de processus du shell au nom du fichier. Mais j'espère qu'il y a une meilleure solution qui n'encombrera pas mon système avec beaucoup de fichiers.
man 1 mktemp
.Réponses:
Pour obtenir la même sortie que vous notez dans votre question, tout ce qui est nécessaire est le suivant:
Vous n'avez pas besoin de se contorsionner. Ces deux lignes feront tout dans n'importe quel shell qui prétend être proche de la compatibilité POSIX.
Mais j'ai aimé ça. Et je voulais démontrer les principes fondamentaux de ce qui rend ce travail un peu meilleur. J'ai donc édité ça un peu. Je l'ai coincé
/tmp
pour l'instant mais je pense que je vais aussi le garder pour moi. C'est ici:ÉCRITURE RAPIDE:
Remarque: ayant récemment appris le yash , je l'ai construit hier. Pour une raison quelconque, il n'imprime pas le premier octet de chaque argument avec la
%c
chaîne - bien que les documents soient spécifiques sur les extensions à caractères larges pour ce format et donc il peut être lié - mais cela fonctionne très bien avec%.1s
Voilà tout. Il y a deux choses principales qui se passent là-haut. Et voici à quoi ça ressemble:
PARSING
$PWD
MAIS QU'EN EST-IL DE L'AUGMENTATION?
Et c'est grâce à POSIX-spécifié
${parameter} $((expansion))
qui conserve ces définitions dans le shell actuel sans exiger que nous les définissions dans un sous-shell séparé, quel que soit l'endroit où nous les évaluons. Et c'est pourquoi cela fonctionne dansdash
etsh
aussi bien que dansbash
etzsh
. Nous n'utilisons aucun échappement dépendant du shell / terminal et nous laissons les variables se tester. C'est ce qui rend le code portable rapide.Le reste est assez simple - il suffit d'incrémenter notre compteur à chaque fois qu'il
$PS2
est évalué jusqu'à ce qu'il soit$PS1
à nouveau réinitialisé. Comme ça:Alors maintenant, je peux:
DASH DEMO
SH DEMO
Cela fonctionne de la même manière dans
bash
oush
:Comme je l'ai dit ci-dessus, le principal problème est que vous devez considérer où vous effectuez votre calcul. Vous n'obtenez pas l'état dans le shell parent - vous n'y calculez donc pas. Vous obtenez l'état dans le sous-shell - c'est donc là que vous calculez. Mais vous faites la définition dans le shell parent.
la source
PS2
? Ceci est la partie délicate. Je ne pense pas que votre solution puisse être appliquée ici. Si vous pensez le contraire, montrez-moi comment.PS1
etPS2
sont des variables spéciales dans le shell qui sont imprimées en tant qu'invite de commande (essayez-le en définissantPS1
une valeur différente dans une nouvelle fenêtre de shell), elles sont donc utilisées très différemment de votre code. Voici quelques informations supplémentaires sur leur utilisation: linuxconfig.org/bash-prompt-basicsecho 'this
à l'invite, puis expliquez comment mettre à jour la valeur dePS2
avant de taper le guillemet simple de fermeture.Avec cette approche (fonction s'exécutant dans un sous-shell), vous ne pourrez pas mettre à jour l'état du processus de shell principal sans passer par des contorsions. Au lieu de cela, organisez l'exécution de la fonction dans le processus maître.
La valeur de la
PROMPT_COMMAND
variable est interprétée comme une commande qui est exécutée avant l'impression de l'PS1
invite.Car
PS2
il n'y a rien de comparable. Mais vous pouvez utiliser une astuce à la place: puisque tout ce que vous voulez faire est une opération arithmétique, vous pouvez utiliser l'expansion arithmétique, qui n'implique pas de sous-shell.Le résultat du calcul arithmétique aboutit à l'invite. Si vous souhaitez le masquer, vous pouvez le passer comme un indice de tableau qui n'existe pas.
la source
C'est un peu intensif en E / S, mais vous devrez utiliser un fichier temporaire pour contenir la valeur du nombre.
Si vous avez besoin d'un fichier séparé par session shell (ce qui semble être une préoccupation mineure; allez-vous vraiment taper des commandes multi-lignes dans deux shells différents en même temps?), Vous devez utiliser
mktemp
pour créer un nouveau fichier pour chaque utilisation.la source
Vous ne pouvez pas utiliser une variable shell de cette façon et vous comprenez déjà pourquoi. Un sous-shell hérite des variables exactement de la même manière qu'un processus hérite de son environnement: toutes les modifications apportées s'appliquent uniquement à lui et à ses enfants et non à un processus ancêtre.
Selon d'autres réponses, la chose la plus simple à faire est de ranger ces données dans un fichier.
Etc.
la source
mktemp
).PS2
est développée par le shell. Vous n'avez pas la possibilité de mettre à jour la valeur d'une variable dans le shell parent à ce moment.Pour référence, voici ma solution en utilisant des fichiers temporaires, qui sont uniques par processus shell, et supprimés dès que possible (pour éviter l'encombrement, comme mentionné dans la question):
la source