Arrêter l'expansion des caractères génériques du shell?

88

Existe-t-il un moyen pour un programme de ligne de commande compilé d'indiquer à bash ou à csh qu'il ne souhaite pas développer de caractères génériques dans ses paramètres?

Par exemple, on pourrait vouloir une commande shell comme:

foo *

pour renvoyer simplement la valeur ASCII numérique de ce caractère.

hotpaw2
la source

Réponses:

119

Non. L'extension a lieu avant que la commande ne soit réellement exécutée.
Vous ne pouvez désactiver le glob avant d'exécuter la commande ou en citant l'étoile.

$ # quote it
$ foo '*'

$ # or escape it
$ foo \*

$ # or disable the glob (noglob)
$ set -f
$ foo *

$ # alternative to set -f
$ set -o noglob
$ # undo it by 
$ set +o noglob
c00kiemon5ter
la source
3
de plus, s'il n'y a rien à développer, il n'y a pas d'expansion. c'est-à-dire avec un vide pwd, echo *c'est juste*
sam boosalis
7
@sam Cela dépend en fait de la façon dont vos options sont définies. De tldp: "Si aucun nom de fichier correspondant n'est trouvé et que l'option shell nullglobest désactivée, le mot reste inchangé. Si l' nullgloboption est définie et qu'aucune correspondance n'est trouvée, le mot est supprimé."
Chris Middleton le
merci, j'aurais dû préciser que c'était juste de l'observation et non de toute compréhension.
sam boosalis
@ c00kiemon5ter Comment annuler le set -f? C'est ça unset -f?
Nam G VU
1
@NamGVUset +f
Yngvar Kristiansen le
62

S'il est vrai qu'une commande elle-même ne peut pas désactiver la globalisation, il est possible pour un utilisateur de dire à un shell Unix de ne pas glober une commande particulière. Ceci est généralement accompli en éditant les fichiers de configuration d'un shell. En supposant que la commande foose trouve le long du chemin de la commande, les éléments suivants doivent être ajoutés au fichier de configuration approprié:

Pour les shells, bash et ksh:

alias foo='set -f;foo';foo(){ command foo "$@";set +f;}

Pour les shells csh et tcsh:

alias foo 'set noglob;\foo \!*;unset noglob'

Pour le shell zsh:

alias foo='noglob foo'

Le chemin de commande n'a pas à être utilisé. Dites que la commande foo est stockée dans le répertoire ~ / bin, alors ce qui précède deviendrait:

Pour les shells, bash et ksh:

alias foo='set -f;foo';foo(){ ~/bin/foo "$@";set +f;}

Pour les shells csh et tcsh:

alias foo 'set noglob;$home/bin/foo \!*;unset noglob'

Pour le shell zsh:

alias foo='noglob ~/bin/foo'

Tout ce qui précède a été testé avec l'OSX 10.9.2 d'Apple. Remarque: lors de la copie du code ci-dessus, veillez à ne pas supprimer les espaces. Ils peuvent être importants.

Mise à jour:

L'utilisateur geira a souligné que dans le cas d'un shell bash

alias foo='set -f;foo';foo(){ ~/bin/foo "$@";set +f;}

pourrait être remplacé par

reset_expansion(){ CMD="$1";shift;$CMD "$@";set +f;}
alias foo='set -f;reset_expansion ~/bin/foo'

ce qui élimine le besoin de la fonction foo.

Certains sites Web utilisés pour créer ce document:

David Anderson
la source
3
Cela aurait dû être la réponse acceptée car elle prouve qu'il est en effet possible de faire ce que le PO veut. Pour des méthodes encore meilleures dans bash, ce lien documente les différentes options: blog.edwards-research.com/2011/05/preventing-globbing
geira
@geira: Parfois, une réponse est acceptée avant qu'une meilleure réponse ne soit publiée. Je pense que c'est peut-être l'un de ces cas. Je pense également que la réponse est la plus utile par les utilisateurs. Remarque: j'ai ajouté votre entrée à ma réponse.
David Anderson
@geira, l'OP veut que le programme compilé communique avec le shell; répondre qu'il est possible de configurer le shell pour qu'il se comporte comme souhaité sur une base commande par commande est une réponse utile, et j'accepterais moi-même celle-ci, mais je vois qu'il est possible de ne pas être d'accord sur le point de savoir si c'est entièrement sur le point.
Charles Duffy
Le fait que cela puisse être fait ne signifie pas que cela doit être fait. Le fait que le comportement du shell change par rapport aux attentes raisonnables de l'utilisateur pour les commandes de sélection semble surprenant et finalement indésirable.
tripleee
@tripleee: Il fut un temps où les gens attendaient des relais et des tubes à vide. On s'attendait à ce que des trous soient percés dans des cartes en carton et du ruban adhésif. Les gens tenaient des règles à calcul plutôt que des calculatrices et des téléphones. Je suppose que ce serait souhaitable pour vous. Je ne me souciais pas beaucoup de ces moments. J'aime voir ce qui est ensuite.
David Anderson
8

L'expansion est effectuée par le shell avant l'exécution de votre programme. Votre programme ne sait pas si une expansion a eu lieu ou non.

   set -o noglob

désactivera l'expansion dans le shell appelant, mais vous devrez le faire avant d'appeler votre programme.

L'alternative est de citer vos arguments par exemple

foo "*"
Brian Agnew
la source
4
setopt semble être une commande spécifique à zsh. Comme l'a dit une autre affiche, pour bash, vous utilisez set -o noglobpour désactiver l'expansion des caractères génériques.
Wirawan Purwanto
Maintenant modifié. Merci
Brian Agnew
1

Attention: s'il n'y a pas de nom correspondant au masque, bash passe l'argument tel quel, sans développement!

Preuve (pa.py est un script très simple, qui imprime juste ses arguments):

 $ ls
f1.cc  f2.cc  pa.py
 $ ./pa.py *.cc
['./pa.py', 'f1.cc', 'f2.cc']
 $ ./pa.py *.cpp
['./pa.py', '*.cpp']
Lesnik
la source
3
Pas toujours. set -o nullglobou shopt -s failglob, et ce comportement changera (de deux manières très différentes).
Charles Duffy