Le choix t'appartient. Si vous ne citez $@
aucune de ses valeurs, faites l' objet d'une expansion et d'une interprétation supplémentaires. Si vous le citez tous les arguments passés, la fonction est reproduite textuellement dans son expansion. Vous ne serez jamais en mesure de gérer de manière fiable les jetons de syntaxe du shell comme &>|
et etc de toute façon sans analyser les arguments vous-même de toute façon - et vous avez donc le choix plus raisonnable de remettre votre fonction l'une des deux:
- Exactement les mots utilisés dans l'exécution d'une seule commande simple avec
"$@"
.
...ou...
- Une autre version développée et interprétée de vos arguments qui ne sont ensuite appliqués que comme une simple commande avec
$@
.
Aucune des deux façons n'est fausse si elle est intentionnelle et si les effets de ce que vous choisissez sont bien compris. Les deux méthodes présentent des avantages l'une par rapport à l'autre, bien que les avantages de la seconde soient rarement susceptibles d'être particulièrement utiles. Encore...
(run_this(){ $@; }; IFS=@ run_this 'ls@-dl@/tmp')
drwxrwxrwt 22 root root 660 Dec 28 19:58 /tmp
... ce n'est pas inutile , mais rarement susceptible d'être d'une grande utilité . Et dans un bash
shell, parce bash
que par défaut ne colle pas une définition de variable à son environnement même lorsque ladite définition est ajoutée à la ligne de commande d'un builtin spécial ou à une fonction, la valeur globale de $IFS
n'est pas affectée et sa déclaration est locale uniquement à l' run_this()
appel.
De même:
(run_this(){ $@; }; set -f; run_this ls -l \*)
ls: cannot access *: No such file or directory
... le globbing est également configurable. Les citations ont un but - elles ne sont pas pour rien. Sans eux, l'expansion du shell subit une interprétation supplémentaire - une interprétation configurable . Auparavant - avec de très vieux shells - qui $IFS
était globalement appliqué à toutes les entrées, et pas seulement aux extensions. En fait, lesdits obus se sont comportés de manière très similaire run_this()
à ce qu'ils ont brisé tous les mots saisis sur la valeur de $IFS
. Et donc, si ce que vous recherchez est ce comportement de shell très ancien, alors vous devriez l' utiliser run_this()
.
Je ne le cherche pas, et j'ai du mal à trouver un exemple utile pour le moment. Je préfère généralement que les commandes exécutées par mon shell soient celles que je tape dessus. Et donc, étant donné le choix, je le ferais presque toujours run_that()
. Excepté...
(run_that(){ "$@"; }; IFS=l run_that 'ls' '-ld' '/tmp')
drwxrwxrwt 22 root root 660 Dec 28 19:58 /tmp
À peu près tout peut être cité. Les commandes s'exécuteront entre guillemets. Cela fonctionne car au moment où la commande est réellement exécutée, tous les mots d'entrée ont déjà subi la suppression des guillemets - qui est la dernière étape du processus d'interprétation des entrées du shell. Ainsi, la différence entre 'ls'
et ls
ne peut avoir d'importance que lorsque le shell interprète - et c'est pourquoi la citation ls
garantit qu'aucun alias nommé ls
n'est substitué à mon ls
mot de commande cité . En dehors de cela, les seules choses affectées par les guillemets sont la délimitation des mots (qui explique comment et pourquoi la citation des variables / espaces blancs fonctionne) et l'interprétation des métacaractères et des mots réservés.
Donc:
'for' f in ...
do :
done
bash: for: command not found
bash: do: unexpected token 'do'
bash: do: unexpected token 'done'
Vous ne pourrez jamais le faire avec run_this()
ou run_that()
.
Mais les noms de fonction, ou $PATH
les commandes d , ou les commandes intégrées s'exécuteront très bien entre guillemets ou sans guillemets, et c'est exactement comment run_this()
et run_that()
fonctionner en premier lieu. Vous ne pourrez rien faire d'utile avec $<>|&(){}
aucun d'entre eux. À court de eval
, c'est.
(run_that(){ "$@"; }; run_that eval printf '"%s\n"' '"$@"')
eval
printf
"%s\n"
"$@"
Mais sans cela, vous êtes contraint aux limites d'une simple commande en raison des guillemets que vous utilisez (même si vous ne le faites pas, car il $@
agit comme une citation au début du processus lorsque la commande est analysée pour les métacaractères) . La même contrainte est vraie pour les affectations et les redirections de ligne de commande, qui sont limitées à la ligne de commande de la fonction. Mais ce n'est pas grave:
(run_that(){ "$@";}; echo hey | run_that cat)
hey
J'aurais pu y <
rediriger l'entrée ou la >
sortie aussi facilement que j'ai ouvert le tuyau.
Quoi qu'il en soit, de manière détournée, il n'y a pas de bonne ou de mauvaise voie ici - chaque voie a ses utilisations. C'est juste que vous devez l'écrire comme vous avez l'intention de l'utiliser, et vous devez savoir ce que vous voulez faire. Citations Omettre peuvent avoir un but - sinon il n'y aurait pas être citations du tout - mais si vous les omettez pour des raisons non pertinentes à votre but, vous êtes juste à écrire du mauvais code. Faites ce que vous voulez dire; J'essaye de toute façon.
run_that
Le comportement est certainement ce à quoi je m'attendais (et s'il y a un espace sur le chemin de la commande?). Si vous vouliez l'autre comportement, sûrement vous le citez sur le site d' appel où vous savez quelles sont les données? Je m'attendrais à appeler cette fonction commerun_that ls -l
, ce qui fonctionne de la même manière dans l'une ou l'autre version. Y a-t-il un cas qui vous a fait vous attendre différemment?