Je voudrais renvoyer une chaîne d'une fonction Bash.
Je vais écrire l'exemple en java pour montrer ce que j'aimerais faire:
public String getSomeString() {
return "tadaa";
}
String variable = getSomeString();
L'exemple ci-dessous fonctionne en bash, mais existe-t-il une meilleure façon de procéder?
function getSomeString {
echo "tadaa"
}
VARIABLE=$(getSomeString)
string
bash
function
return-value
Tomas F
la source
la source
function funcName {
syntaxe héritée pré-POSIX est héritée du début de ksh (où il y avait des différences sémantiques que bash n'honore pas).funcName() {
, avec nofunction
, doit être utilisé à la place; voir wiki.bash-hackers.org/scripting/obsoletefunction myFunction { blah; }
va bien; c'estfunction myFunction() { blah }
que ce n'est pas bien, c'est à dire l'utilisation de parenthèses avec la fonction mot-clé.Réponses:
Il n'y a pas de meilleure façon que je sache. Bash ne connaît que les codes d'état (entiers) et les chaînes écrites sur la sortie standard.
la source
somefunction && echo 'success'
). Si vous pensez à une fonction comme juste une autre commande, cela a du sens; les commandes ne «renvoient» rien à la sortie autre qu'un code d'état, mais elles peuvent sortir des choses entre-temps que vous pouvez capturer.Vous pouvez demander à la fonction de prendre une variable comme premier argument et de modifier la variable avec la chaîne que vous souhaitez renvoyer.
Imprime "foo bar rab oof".
Edit : ajout de citations à l'endroit approprié pour permettre aux espaces dans la chaîne de répondre au commentaire de @Luca Borrione.
Modifier : à titre de démonstration, voir le programme suivant. Il s'agit d'une solution polyvalente: elle vous permet même de recevoir une chaîne dans une variable locale.
Cela imprime:
Edit : démontrant que la valeur de la variable d'origine est disponible dans la fonction, comme l'a incorrectement critiqué par @Xichen Li dans un commentaire.
Cela donne une sortie:
la source
fgm
réponse écrite de manière simplifiée? Cela ne fonctionnera pas si la chaînefoo
contient des espaces blancs, tandis quefgm
celle de .. sera comme il le montre.\$$1
. Si vous cherchez quelque chose de différent, faites-le moi savoir.printf '%q' "$var"
. % q est une chaîne de format pour l'échappement du shell. Ensuite, passez-le simplement cru.Toutes les réponses ci-dessus ignorent ce qui a été déclaré dans la page de manuel de bash.
Exemple de code
Et sortie
Sous pdksh et ksh également, ce script fait de même!
la source
Bash, depuis la version 4.3, février 2014 (?), A un support explicite pour les variables de référence ou les références de nom (namerefs), au-delà de "eval", avec les mêmes performances bénéfiques et effet d'indirection, et qui peuvent être plus clairs dans vos scripts et aussi plus difficiles pour "oublier" eval "et devoir corriger cette erreur":
et aussi:
Par exemple ( EDIT 2 : (merci Ron), le nom de variable interne à la fonction (préfixé), pour minimiser les conflits de variables externes, qui devrait enfin répondre correctement, le problème soulevé dans les commentaires de Karsten):
et tester cet exemple:
Notez que la commande bash "declare", lorsqu'elle est utilisée dans une fonction, rend la variable déclarée "locale" par défaut, et "-n" peut également être utilisée avec "local".
Je préfère distinguer les variables "déclaration importante" des variables "locales ennuyeuses", donc l'utilisation de "déclarer" et "local" de cette manière fait office de documentation.
EDIT 1 - (Réponse au commentaire ci-dessous par Karsten) - Je ne peux plus ajouter de commentaires ci-dessous, mais le commentaire de Karsten m'a fait réfléchir, j'ai donc fait le test suivant qui FONCTIONNE BIEN, AFAICT - Karsten si vous lisez ceci, veuillez fournir un ensemble exact des étapes de test à partir de la ligne de commande, montrant le problème que vous supposez exister, car ces étapes suivantes fonctionnent très bien:
(Je l'ai exécuté tout à l'heure, après avoir collé la fonction ci-dessus dans un terme bash - comme vous pouvez le voir, le résultat fonctionne très bien.)
la source
declare
des variables locales sont créées à l'intérieur des fonctions (cette information n'est pas donnée parhelp declare
): "... Lorsqu'elles sont utilisées dans une fonction, déclarer et composer rendent chaque nom local, comme avec la commande locale, sauf si le - l'option g est fournie ... "K=$1; V=$2; eval "$A='$V'";
, mais une erreur (par exemple un paramètre vide ou omis), et ce serait plus dangereux. @zenaan, le problème soulevé par @Karsten s'applique si vous choisissez "message" comme nom de variable de retour, au lieu de "ret".Comme bstpierre ci-dessus, j'utilise et recommande l'utilisation de nommer explicitement les variables de sortie:
Notez l'utilisation de la citation du $. Cela évitera d'interpréter le contenu en
$result
tant que caractères spéciaux du shell. J'ai trouvé que c'est un ordre de grandeur plus rapide que l'result=$(some_func "arg1")
idiome de capture d'un écho. La différence de vitesse semble encore plus notable en utilisant bash sur MSYS où la capture stdout à partir d'appels de fonction est presque catastrophique.Il est correct d'envoyer des variables locales car les sections locales sont étendues dynamiquement dans bash:
la source
echo
intérieur d'une fonction, combinée à la substitution de commandes!Vous pouvez également capturer la sortie de la fonction:
Ça a l'air bizarre, mais c'est mieux que d'utiliser des variables globales à mon humble avis. Le passage des paramètres fonctionne comme d'habitude, il suffit de les mettre entre accolades ou backticks.
la source
La solution la plus simple et la plus robuste consiste à utiliser la substitution de commandes, comme d'autres l'ont écrit:
L'inconvénient est la performance car cela nécessite un processus distinct.
L'autre technique suggérée dans cette rubrique, à savoir le passage du nom d'une variable à affecter en tant qu'argument, a des effets secondaires, et je ne le recommanderais pas dans sa forme de base. Le problème est que vous aurez probablement besoin de certaines variables dans la fonction pour calculer la valeur de retour, et il peut arriver que le nom de la variable destinée à stocker la valeur de retour interfère avec l'une d'entre elles:
Bien sûr, vous ne pouvez pas déclarer les variables internes de la fonction comme locales, mais vous devez toujours le faire car sinon vous pouvez, par contre, écraser accidentellement une variable non liée de la portée parent s'il y en a une avec le même nom .
Une solution de contournement possible est une déclaration explicite de la variable passée comme globale:
Si le nom "x" est passé en argument, la deuxième ligne du corps de la fonction remplacera la déclaration locale précédente. Mais les noms eux-mêmes peuvent encore interférer, donc si vous avez l'intention d'utiliser la valeur précédemment stockée dans la variable passée avant d'y écrire la valeur de retour, sachez que vous devez la copier dans une autre variable locale au tout début; sinon le résultat sera imprévisible! En outre, cela ne fonctionnera que dans la version la plus récente de BASH, à savoir 4.2. Un code plus portable pourrait utiliser des constructions conditionnelles explicites avec le même effet:
La solution la plus élégante est peut-être simplement de réserver un nom global pour les valeurs de retour de fonction et de l'utiliser de manière cohérente dans chaque fonction que vous écrivez.
la source
eval
etdeclare -n
. La solution de contournement d'avoir un seul nom de variable dédié commeresult
pour tous les paramètres de sortie semble la seule solution qui ne nécessite pas de fonctions pour connaître tous ses appelants pour éviter les conflits.Comme mentionné précédemment, la manière "correcte" de renvoyer une chaîne à partir d'une fonction consiste à substituer une commande. Dans le cas où la fonction doit également sortir sur la console (comme @Mani le mentionne ci-dessus), créez un fd temporaire au début de la fonction et redirigez-le vers la console. Fermez le fd temporaire avant de renvoyer votre chaîne.
exécuter un script sans paramètres produit ...
j'espère que cela aide les gens
-Andy
la source
3>&1
à la tête du script, puis en manipulant&1
&3
et un autre espace réservé&4
au sein de la fonction. Moche tout autour, cependant.Vous pouvez utiliser une variable globale:
Cela donne
la source
Pour illustrer mon commentaire sur la réponse d'Andy, avec une manipulation supplémentaire du descripteur de fichier pour éviter l'utilisation de
/dev/tty
:Toujours méchant, cependant.
la source
La façon dont vous l'avez est la seule façon de le faire sans casser la portée. Bash n'a pas de concept de types de retour, juste des codes de sortie et des descripteurs de fichiers (stdin / out / err, etc.)
la source
S'adresser à Vicky Ronnen tête haute, en considérant le code suivant:
va donner
Peut-être que le scénario normal consiste à utiliser la syntaxe utilisée dans la
test_inside_a_func
fonction, vous pouvez donc utiliser les deux méthodes dans la majorité des cas, bien que la capture de la sortie soit la méthode la plus sûre fonctionnant toujours dans toutes les situations, imitant la valeur de retour d'une fonction que vous pouvez trouver dans d'autres langues, commeVicky Ronnen
indiqué correctement.la source
Je pense que les options ont toutes été énumérées. Le choix d'un peut se résumer à une question du meilleur style pour votre application particulière, et dans cette veine, je veux offrir un style particulier que j'ai trouvé utile. En bash, les variables et les fonctions ne sont pas dans le même espace de noms. Ainsi, le traitement de la variable du même nom comme la valeur de la fonction est une convention que je trouve minimise les conflits de noms et améliore la lisibilité, si je l'applique rigoureusement. Un exemple de la vie réelle:
Et, un exemple d'utilisation de ces fonctions:
Comme vous pouvez le voir, le statut de retour est là pour que vous puissiez l'utiliser lorsque vous en avez besoin, ou ignorer si vous ne le faites pas. La variable "retournée" peut également être utilisée ou ignorée, mais bien sûr seulement après l'appel de la fonction.
Bien sûr, ce n'est qu'une convention. Vous êtes libre de ne pas définir la valeur associée avant de retourner (d'où ma convention de toujours l'annuler au début de la fonction) ou de piétiner sa valeur en appelant à nouveau la fonction (éventuellement indirectement). Pourtant, c'est une convention que je trouve très utile si je me retrouve à faire un usage intensif des fonctions bash.
Par opposition au sentiment que c'est un signe que l'on devrait par exemple "passer à perl", ma philosophie est que les conventions sont toujours importantes pour gérer la complexité de n'importe quel langage.
la source
Vous pouvez
echo
une chaîne, mais attrapez-la par piping (|
) la fonction vers autre chose.Vous pouvez le faire avec
expr
, bien que ShellCheck signale cette utilisation comme obsolète.la source
myfunc | read OUTPUT ; echo $OUTPUT
ne rapporte rien.myfunc | ( read OUTPUT; echo $OUTPUT )
obtient la valeur attendue et clarifie ce qui se passe sur le côté droit. Mais bien sûr, OUTPUT n'est pas disponible là où vous en avez besoin ...Ils posent un problème majeur de tout schéma de «variable de sortie nommée» où l'appelant peut transmettre le nom de la variable (que ce soit en utilisant
eval
oudeclare -n
) est un alias par inadvertance, c'est-à-dire des conflits de noms: du point de vue de l'encapsulation, il est horrible de ne pas pouvoir ajouter ou renommer une variable locale dans une fonction sans vérifier d'abord TOUS les appelants de la fonction pour s'assurer qu'ils ne veulent pas passer le même nom que le paramètre de sortie. (Ou dans l'autre sens, je ne veux pas avoir à lire la source de la fonction que j'appelle juste pour m'assurer que le paramètre de sortie que j'ai l'intention d'utiliser n'est pas un local dans cette fonction.)La seule solution consiste à utiliser une seule variable de sortie dédiée comme
REPLY
(comme suggéré par Evi1M4chine ) ou une convention comme celle suggérée par Ron Burk .Cependant, il est possible que les fonctions utilisent une variable de sortie fixe en interne , puis ajoutent du sucre par-dessus pour masquer ce fait à l'appelant , comme je l'ai fait avec la
call
fonction dans l'exemple suivant. Considérez cela comme une preuve de concept, mais les points clés sontREPLY
, et peut également retourner un code de sortie comme d'habitudeREPLY
(voir l'wrapper
exemple). Le code de sortie de la fonction est transmis, donc en les utilisant par exemple dans unif
ouwhile
ou de travaux de constructions similaires comme prévu.La raison pour laquelle cela fonctionne est que la
call
fonction elle-même n'a pas de sections locales et n'utilise aucune variable autre queREPLY
, évitant tout risque de conflits de noms. Au moment où le nom de la variable de sortie définie par l'appelant est attribué, nous sommes effectivement dans la portée de l'appelant (techniquement dans la portée identique de lacall
fonction), plutôt que dans la portée de la fonction appelée.Production:
la source
modèle bash pour renvoyer les objets de valeur scalaire et de tableau :
définition
invocation
la source
Dans mes programmes, par convention, c'est à cela que sert la
$REPLY
variable préexistante , qui l'read
utilise dans ce but précis.Ce
echo
esMais pour éviter les conflits, toute autre variable globale fera l'affaire.
Si cela ne suffit pas, je recommande la solution de Markarian451 .
la source
la source