GNU trouve et masque les {} pour quelques obus - lequel?

34

La page de manuel de GNU Find indique les états suivants:

-exec command ;
    [...] The  string `{}'  is  replaced  by the current 
    file name being processed everywhere it occurs in the 
    arguments to the command, not just in arguments where 
    it is alone, as in some  versions  of  find.
    Both  of  these  constructions might need to be escaped 
    (with a `\') or quoted to protect them from expansion 
    by the shell. 

Cela va de l'homme à find(GNU findutils) 4.4.2.

Maintenant, j'ai testé cela avec bash et dash, et les deux n'ont pas besoin d' {}être masqués. Voici un test simple:

find /etc -name "hosts" -exec md5sum {} \; 

Y at-il une coquille, pour laquelle j'ai vraiment besoin de masquer les accolades? Notez que cela ne dépend pas de savoir si le fichier trouvé contient un blanc (appelé depuis bash):

find ~ -maxdepth 1 -type d -name "U*" -exec ls -d {} \; 
/home/stefan/Ubuntu One

Cela change si le fichier trouvé est passé dans un sous-shell:

find ~ -maxdepth 3 -type d -name "U*" -exec bash -c 'ls -d {}' \; 
ls: cannot access /home/stefan/Ubuntu: No such file or directory
ls: cannot access One: No such file or directory

qui peut être résolu par:

find ~ -maxdepth 3 -type d -name "U*" -exec bash -c 'ls -d "$0"' {} \;

contrairement à:

find ~ -maxdepth 3 -type d -name "U*" -exec bash -c 'ls -d "{}"' \; 
/home/stefan/Ubuntu One

mais ce n'est pas ce dont parle la page de manuel, n'est-ce pas? Alors, quelle coquille traite {}d'une manière différente?

Utilisateur inconnu
la source
@Volker Siegel: Votre modification a peut-être eu lieu dans de bonnes intentions, mais j'ai vérifié mon manuel de recherche actuel et vos corrections sont erronées. Vous avez également raté l'occasion de résumer vos modifications, ce qui est une mauvaise habitude. J'ai donc annulé vos modifications. Désolé, camarade.
utilisateur inconnu
Oh, merci de l'annuler si quelque chose se cassait. Je me souvenais que le compilateur de texte qui génère le format de page de manuel utilisé pour générer ces "citations typographiques" en tant qu'artefact de la définition de rendu. Il peut également rendre à TeX pour un format d'impression parfait. J'ai remarqué les citations parce qu'elles confondaient la coloration syntaxique. J'ai supposé que la première citation inhabituelle était fausse lorsqu'elle était utilisée dans le code, et je le suppose toujours. Notez que les deux modifications concernent le texte de description, pas le code. Donc, si nous les voyons comme une typographie - un rendu esthétique - ils ont raison.
Volker Siegel
On dirait que dans le rendu de la sortie info, la même citation est utilisée des deux côtés. Il ne fait aucun doute que mon changement l'a rendu différent de l'original, vous avez raison. Mais cela a-t-il causé des problèmes? (Je considère la première citation comme un bug dans la définition du rendu de l'homme, c'est le seul cas de typographie à ma connaissance.)
Volker Siegel
Je viens de vérifier: "{}" ne fonctionne pas en ligne de commande. C'est techniquement correct, mais je n'aime pas le fait qu'un utilisateur non averti reçoive une erreur étrange lorsqu'il tente de le copier-coller.
Volker Siegel
@VolkerSiegel: Il s'agit de texte en prose, pas de code, que doit donc copier / coller un utilisateur ici? Et c'est une citation de la page de manuel de 2011. Je ne vois aucune valeur de corriger le passage pour indiquer ensuite pourquoi j'ai apporté des corrections à la page de manuel. Le sujet est assez compliqué. Si telle était votre question, je ne tenterais pas de vous convaincre, de citer la page de manuel avec précision, mais pour ma question, je ne suis pas d'humeur à faire des compromis. Citation est citation.
utilisateur inconnu

Réponses:

26

Résumé : Si jamais un shell s’agrandissait {}, c’est maintenant du passé .

Dans le shell Bourne et dans les shell compatibles POSIX, les accolades ( {et }) sont des caractères ordinaires (contrairement à (et )qui sont des délimiteurs de mots comme ;et &, et [et ]qui sont des caractères globaux). Les chaînes suivantes sont toutes supposées être imprimées littéralement:

$ echo { } {} {foo,bar} {1..3}
{ } {} {foo,bar} {1..3}

Un mot constitué d'une seule accolade est un mot réservé , qui n'est spécial que s'il s'agit du premier mot d'une commande.

Ksh implémente le développement d'accolade en tant qu'extension incompatible du shell Bourne. Cela peut être désactivé avec set +B. Bash émule ksh à cet égard. Zsh implémente également l'expansion des corsets; il peut être désactivé avec set +Iou setopt ignore_bracesou emulate sh. {}En aucun cas, aucun de ces shells ne se développe , même s'il s'agit d'une sous-chaîne d'un mot (par exemple foo{}bar), en raison de l'utilisation courante dans les arguments de findet xargs.

Single Unix v2 note que

Dans certains systèmes historiques, les accolades sont traitées comme des opérateurs de contrôle. Pour faciliter les futures activités de normalisation, les applications portables devraient éviter d’utiliser des accolades sans guillemets pour représenter les caractères eux-mêmes. Il est possible qu'une future version de la norme ISO / IEC 9945-2: 1993 exige {et }soit traitée individuellement en tant qu'opérateurs de contrôle, bien que le jeton {}constitue probablement une exception spéciale dans ce cas en raison de la find {}structure souvent utilisée .

Cette note a été supprimée dans les versions suivantes de la norme. les exemples pourfind des utilisations non citées de {}, de même que les exemples pourxargs . Il y a peut-être eu des coquilles Bourne historiques où il a {}fallu citer, mais il s'agirait vraiment de vieux systèmes hérités.

Les implémentations csh que j'ai sous la main (OpenBSD 4.7, BSD csh sur Debian , tcsh) se développent toutes {foo}en foolaissant de côté {}.

Gilles, arrête de faire le mal
la source
1
@geekosaur: Seul un petit sous-ensemble de démarques fonctionne dans les commentaires . Je ne sais pas ce que vous essayez de dire. S'il s'agit de l'extension d'accolade de ksh et al, lisez mon paragraphe commençant par «Ksh implémente l'extension d'accolade comme une extension incompatible».
Gilles 'SO- arrête d'être méchant'
2
C'était bash(voir $BASH_VERSION). L’expansion du corset est très bien vivante.
geekosaur
2
Ce fut le point. La {}syntaxe est originaire de csh, mais {}étendue à la chaîne vide. Les nouveaux obus reconnaissent que c'est absurde, mais il y a encore du vieux csh.
geekosaur
1
@geekosaur: Pouvez-vous dire quelle version spécifique de csh sur quelle plate-forme spécifique? Je préférerais le tester moi-même (si cela est possible sur Linux) ou être assuré que la personne le testera lui-même.
utilisateur inconnu
1
@geekosaur, {}foos'étendrait à foo, mais étendrait {}à {}(sauf quand dans les backticks, mais citer ne aiderait pas) et a été documenté en tant que tel. Je l'ai vérifié pour le csh de 2BSD (première version), 2.79BSD, 2.8BSD et 2.11BSD.
Stéphane Chazelas
12

Le {}besoin d'être cité dans les versions du fishshell avant la version 3.0.0.

$ fish -c 'echo find -exec {} \;'
find -exec  ;

Et dans le shell rc (également akangabasé sur rc, mais pas es):

$ rc -c "echo find -exec {} ';'"
line 1: syntax error near '{'

Ce ne sont probablement pas les réservoirs que les auteurs de la documentation de découverte GNU avaient en tête lorsqu'ils ont écrit ce texte depuis fishsa première publication en 2005 (alors que ce texte ou similaire existait déjà en 1994) et qu'il rcne s'agissait pas à l'origine d'un shell Unix.

Certaines rumeurs disent que certaines versions de csh(le shell qui a introduit le développement par accolade) en ont besoin. Mais il est difficile d’en attribuer le mérite à ceux qui se sont produits depuis la première version de csh2BSD. Ici comme testé dans un émulateur PDP11:

# echo find -exec {} \;
find -exec {} ;

Et la page de manuel de 2BSD cshindique clairement :

Dans des cas spéciaux, "{", "}" et "{}" sont passés sans être dérangés.

Donc, je trouverais cela très étrange si une version ultérieure de csh ou de tcsh le cassait plus tard.

Cela aurait pu être de contourner certains bugs dans certaines versions. Toujours avec ce csh 2BSD (c'est la même chose dans 2.79BSD, 2.8BSD, 2.11BSD):

# csh -x
# echo foo {} bar
echo foo {} bar
foo {} bar
# echo `echo foo {} bar`
echo `echo foo {} bar`
echo foo {} bar
foo  bar

Citant n'aide pas si:

# echo `echo foo '{}' bar`
echo `echo foo '{}' bar`
echo foo {} bar
foo  bar

Vous pouvez citer toute la substitution de commande:

# echo "`echo foo {} bar`"
echo `echo foo {} bar`
echo foo {} bar
foo {} bar

Mais cela passe un argument à cet écho extérieur.

En cshou tcsh, vous auriez besoin de citer le {}quand pas seul comme dans:

find . -name '*.txt' -type f -exec cp {} '{}.back' \;

(Bien que ce type d’ findutilisation ne soit pas portable car certains findne s’agrandissent {}que par eux-mêmes).

Stéphane Chazelas
la source
1

En un mot, csh. bashet d'autres coques modernes reconnaissent que l'utilisateur ne demande probablement pas une extension null Brace. (Moderne cshest en fait tcshet peut également traiter de manière {}saine maintenant.)

geekosaur
la source
Cela fait plaisir à entendre, mais je demande l'inverse, une coquille pour laquelle elle ne s'en occupe pas sainement.
utilisateur inconnu
Vous supposez que quelqu'un entrerait et déchirerait la référence de la page d'information à des citations supplémentaires simplement parce que les systèmes Linux sont tous plus récents csh. Tout le monde n’exécute pas les utilitaires GNU sous Linux; en fait, il est assez courant de les installer sur des systèmes Unix commerciaux plus anciens dont les commandes groupées sont limitées. (Le remplacement cshsur ces systèmes est moins probable, car les scripts système peuvent s'appuyer sur les particularités de l'original csh, et même si les utilisateurs étaient tous configurés pour utiliser une nouvelle version csh, il rootfaudrait presque certainement conserver la version
fournie
2
Non, je suis en discussion avec un type qui dit que, dans notre wiki, nous devrions donner le conseil d'utiliser "{}" tout le temps, car la page de manuel le dit. Et maintenant, j'aimerais savoir s'il y a un shell que je n'utilise pas, comme ksh, zsh, tcsh, csh ou XYZsh et que je ne connais pas, pour lequel cette affirmation est vraie, ou si je peux honnêtement assumer que il n'y en a pas. S'il y a des shells pour différents Unix qui ont besoin du "{}", ce serait une bonne explication de la raison pour laquelle la phrase est toujours dans la page de manuel, mais n'est pas un conseil approprié pour les débutants sous Linux.
utilisateur inconnu
Maintenant, je me demande si pdkshla bonne chose à faire… bien que la bonne réponse à cette question est probablement «le réel kshest le logiciel libre, ces temps-ci».
geekosaur
4
Pdksh, comme mksh, ksh93, bash et zsh, n'agrandit les accolades que s'il existe une virgule entre les deux (ou ..pour ksh93, bash et zsh). Only (t) csh se développe {foo}en foo, et même il reste {}seul (au moins sur les BSD récents).
Gilles 'SO- arrête d'être méchant'