L'espace n'est-il pas autorisé dans un nom de fichier?

31

Il est dit que sous Unix et Linux en général, vous devez éviter d'avoir des espaces dans le nom de fichier d'un fichier (fichier ordinaire, dir, lien, fichier de périphérique, ...).

Mais je fais ça tout le temps. Pour un nom de fichier avec un espace à l'intérieur,

  • Dans Nautilus, le caractère espace est affiché comme un espace.
  • Dans le terminal Bash, j'utilise soit \ pour représenter un espace, soit pour enfermer le nom de fichier dans une paire de guillemets doubles.
  • dans les fichiers de certaines applications (Nautilus, je ne sais pas si le système d'exploitation le fera également), le nom de fichier est écrit avec l'espace remplacé par %20.

Un espace n'est-il vraiment pas autorisé dans un nom de fichier?

Comment utilisez-vous ou gérez-vous correctement un espace dans un nom de fichier?

Tim
la source
17
C'est permis mais c'est vraiment, vraiment ennuyeux. Il n'y a aucune raison à cela. Ne le fais pas.
Courses de légèreté avec Monica
3
Vous pouvez également créer un fichier nommé -rf ~(use touch -- "-rf ~"), mais je ne le recommanderais pas.
Ian D. Scott
5
Vous pouvez le faire, c'est autorisé, comme créer un script d'autodestruction appelé "cd" mais vous ne devriez pas le faire. Votre fichier est déjà différent dans 3 outils différents, n'est-ce pas assez mauvais?
Falco
7
Tout le monde ne pense pas que c'est vraiment, vraiment ennuyeux. Et "il n'y a aucune raison" est si manifestement faux qu'il n'a pas besoin d'être réfuté. J'ai cédé et appris à gérer correctement les espaces il y a des années, et pour la plupart, ce n'est vraiment pas un gros problème.
2
@snailboat Les espaces sont un symptôme du vrai problème qui est un manque de standardisation. Les systèmes de fichiers Unix autorisent les «noms» de fichiers vers des objets binaires binaires presque illimités. Les seuls octets illégaux sont 0 et 47 (le /séparateur). L'utilisation des 254 octets restants ouvre la porte à toutes les manières de "noms" indescriptibles de eldritch. Évidemment, c'est fou, mais tout le monde n'est pas d'accord sur ce qu'est "sain d'esprit", et différents personnages briseront différents outils. L'intersection de la santé mentale de chacun est assez petite .
jw013

Réponses:

48

Les espaces, et en fait tous les caractères sauf /et NUL, sont autorisés dans les noms de fichiers. La recommandation de ne pas utiliser d'espaces dans les noms de fichiers vient du risque qu'ils soient mal interprétés par un logiciel qui les prend mal en charge. On peut dire que ce logiciel est bogué. Mais sans doute, les langages de programmation tels que les scripts shell facilitent trop l'écriture de logiciels qui se cassent lorsqu'ils sont présentés avec des noms de fichiers avec des espaces, et ces bogues ont tendance à passer car les scripts shell ne sont pas souvent testés par leurs développeurs en utilisant des noms de fichiers avec des espaces dans leur.

Les espaces remplacés par %20n'apparaissent pas souvent dans les noms de fichiers. Cela est principalement utilisé pour les URL (Web). Bien qu'il soit vrai que le codage% à partir d'URL fait parfois son chemin dans les noms de fichiers, souvent par accident.

Celada
la source
6
C'est "encodage URL" ou "encodage en pourcentage" en.wikipedia.org/wiki/URL_encoding Selon cela, le nom le plus approprié est probablement "encodage URI", mais les gens trouvent l' URL plus facile à dire que l' URI , c'est donc une forme courante de abusif. Notez que l'ensemble des caractères réservés dans les URI est plus grand que pour les noms de fichiers * nix.
goldilocks
1
@Tim Je ne sais pas que vous pouvez spécifier un caractère NUL dans n'importe quel argument de ligne de commande dans bash. J'ai essayé quelques choses telles que le citer avec Ctrl-V et quelque chose comme $(echo -e \\0)ça, mais cela n'a pas fonctionné. Le fait est que la raison pour laquelle NUL ne peut pas être utilisé dans les noms de fichiers est qu'il ne peut pas être utilisé dans les chaînes C (car c'est le terminateur de chaîne) et toutes les API sous-jacentes ainsi que pratiquement toutes les chaînes gérées par les programmes C utilisent ce format . Puisqu'il bashest écrit en C, il peut simplement ne prendre en charge aucune chaîne contenant NUL. Je peux me tromper, il pourrait y avoir un moyen obscur ...
Celada
1
Cela dépend du contexte. Les fonctions de chaîne ne comptent généralement pas le null final (ou plutôt, le premier null est la fin de la chaîne, même s'il y a des éléments après), donc dans ce sens, il a une longueur nulle et serait donc considéré comme vide.
goldilocks
3
@Celada bien sûr, vous pouvez utiliser NULet bash, vous avez besoin $'\0'. Par exemple:find . -print0 | while read -d $'\0' f; do echo "$f"; done
terdon
1
@goldilocks Les gens prononcent-ils réellement l'URL comme 'url', rimant à peu près avec 'earl'?
Miles Rout
17

Les espaces sont autorisés dans les noms de fichiers, comme vous l'avez observé.

Si vous regardez l'entrée "la plupart des systèmes de fichiers UNIX" dans ce graphique dans wikipedia , vous remarquerez:

  • Tout jeu de caractères 8 bits est autorisé. Nous pouvons également subsumer ASCII 7 bits sous ce parapluie, car il s'agit d'un sous-ensemble de divers ensembles 8 bits et est toujours implémenté à l'aide d'octets 8 bits.

  • Les seuls caractères interdits sont /et "null". "Null" fait référence à un octet zéro, mais ceux-ci ne sont de toute façon pas autorisés dans les données de texte.

Cependant , si vous utilisez le shell, vous pouvez vous rendre compte qu'il existe certains caractères qui créeront un problème, le plus important *, qui est un opérateur de remplacement POSIX.

Selon la façon dont vous voulez définir les "tracas", vous pouvez y inclure des espaces (espaces, tabulations, nouvelles lignes, etc.), car cela crée le besoin de citer avec "". Mais cela est inévitable, car les espaces sont autorisés, alors ...

Comment utilisez-vous ou gérez-vous correctement un espace dans un nom de fichier?

Dans un contexte shell / ligne de commande, encapsulez le nom de fichier entre guillemets simples ou doubles (mais notez qu'il ne s'agit pas des mêmes problèmes WRT), ou échappez aux espaces avec \, par exemple:

> foo my\ file\ with\ spaces\ in\ the\ name
boucle d'or
la source
1
Comment spécifiez-vous le caractère NUL dans bash? Je veux le tester dans un nom de fichier.
Tim
1
Tu ne peux pas. La "sémantique execve" fait référence au fait qu'en C (et dans tous les autres langages que je connais), les chaînes de texte sont terminées par null. Le shell est implémenté en C. La chose la plus sournoise à laquelle je puisse penser est touch $(echo -e "foo\00bar")- les -eprocessus en \0Ntant que valeur octale, mais ils se perdent quelque part, car cela crée simplement un fichier nommé foobar. Bien sûr, NULL n'est pas imprimable, mais je vous garantis qu'il a disparu à cause de la restriction de la chaîne C.
goldilocks
"les chaînes de texte sont terminées par null" -> Pour expliquer davantage: les chaînes sont toujours stockées avec un octet zéro à la fin, c'est pourquoi il "n'est pas autorisé" dans le texte: si vous en insérez une, vous avez effectivement terminé la chaîne à ce moment. Par exemple, foo[NULL]barfinirait comme foopour la plupart des intentions et des fins. Le fait que cela ne se produise pas echo -emontre que le NULL a été élagué quelque part.
goldilocks
5
Une grande majorité des langages de programmation autorisent les caractères nuls dans les chaînes. Il se trouve que le langage principal qui n'est pas le C, sur lequel Unix est construit - et la plupart des shells Unix n'autorisent pas non plus les caractères nuls dans les chaînes. Dans tous les cas, @Tim, toutes les interfaces Unix utilisent des chaînes terminées par null, donc un octet nul est la seule chose que vous ne pouvez jamais avoir dans un nom de fichier (plus /qui est le séparateur de répertoire et ne peut pas être cité, donc peut être dans un chemin d'accès mais pas dans un nom de fichier).
Gilles 'SO- arrête d'être méchant'
1
... mais [plus encore). Pas quelque chose que je ferais trop souvent, de toute façon. À mon avis, il n'y a aucune raison qu'ils soient dans des données textuelles. J'aurais corrigé cela, mais c'est un commentaire.
goldilocks
3

La raison est en grande partie historique - WAY retour dans la brume des espaces temporels n'était pas autorisé dans les noms de fichiers, donc les espaces ont été utilisés comme séparateurs de mots clés / noms de fichiers. Les futurs interpréteurs de shell devaient être rétrocompatibles avec les anciens scripts, et nous sommes donc coincés avec le mal de tête que nous avons aujourd'hui.

Les développeurs de processus qui n'ont pas besoin de beaucoup traiter avec les humains peuvent rendre les choses beaucoup plus faciles en supprimant complètement les espaces. Apple le fait, le contenu de / System / Library / CoreServices / contient très peu d'espaces, les programmes avec espaces sont ouverts au nom de l'utilisateur et WouldLookStrangeIfCamelCased. Des chemins similaires Unix uniquement évitent également les espaces.

(anecdote quelque peu apparentée: au milieu des années 90, un drone Windows a dit "Nommez une chose que vous pouvez faire sur un Mac que je ne peux pas faire sous Windows" -> "Utilisez 12 caractères dans un nom de fichier." -> Silence. Les espaces étaient également possible dans ces 12 caractères)

Paul
la source
1
J'avais l'habitude d'utiliser V6 Unix (c.1978). Les espaces étaient alors autorisés. Une tâche que j'avais était d'écrire un programme pour analyser le système de fichiers (en utilisant les E / S disque directes) et de rechercher un fichier qui avait des espaces et des espaces arrière dans son nom.
wallyk
suppriment-ils tous les espaces - ou les noms de fichiers contiennent-ils très peu d'espaces?
mikeserv
2

Donc oui, comme cela est dit à plusieurs reprises ailleurs, un nom de fichier peut contenir presque n'importe quel caractère. Mais il faut dire qu'un nom de fichier n'est pas un fichier. Il a un certain poids en tant qu'attribut de fichier dans la mesure où vous avez généralement besoin d'un nom de fichier pour ouvrir un fichier, mais le nom d' un fichier ne pointe que vers le fichier réel. Il s'agit d'un lien, stocké dans le répertoire qui l'a enregistré, à côté du numéro d'inode - qui est une approximation beaucoup plus proche d'un fichier réel .

Alors, vous savez, appelez ça comme vous voulez. Le noyau s'en fiche - toutes les références de fichiers qu'il gérera traiteront de toute façon les vrais numéros d'inode. Le nom de fichier est une chose pour la consommation humaine - si vous voulez en faire une chose folle, eh bien, c'est votre système de fichiers. Ici, je vais faire des trucs fous:

Je vais d'abord créer 20 fichiers et les nommer avec uniquement des espaces, chaque nom de fichier contenant un espace de plus que le dernier:

until [ $((i=$i+1)) -gt 20 ]
do  v=$v' ' && touch ./"$v"
done

C'est un peu drôle. Regardez mon ls:

ls -d ./*
./      ./          ./              ./                  ./                 
./      ./          ./              ./                  ./                  
./      ./          ./              ./                  ./                   
./      ./          ./              ./                  ./     

Maintenant, je vais refléter ce répertoire:

set -- * ; mkdir ../mirror
ls -i1qdU -- "$@" |
sh -c 'while read inum na
    do  ln -T "$1" ../mirror/$inum
    shift ; done' -- "$@"
ls -d ../mirror/*

Voici ../mirror/le contenu de:

../mirror/423759  ../mirror/423764  ../mirror/423769  ../mirror/423774
../mirror/423760  ../mirror/423765  ../mirror/423770  ../mirror/423775
../mirror/423761  ../mirror/423766  ../mirror/423771  ../mirror/423776
../mirror/423762  ../mirror/423767  ../mirror/423772  ../mirror/423777
../mirror/423763  ../mirror/423768  ../mirror/423773  ../mirror/423778

D'accord, mais vous demandez peut-être - mais à quoi ça sert? Comment savoir lequel est lequel? Comment pouvez-vous être sûr d'avoir lié le bon numéro d'inode au bon nom de fichier?

Bien...

echo "heyhey" >>./'    ' 
tgt=$(ls -id ./'    ')
cat ../mirror/${tgt%% .*} \
    $(ls -1td ../mirror/* | head -n1) 

SORTIE

heyhey
heyhey

Voir, le numéro d'inode contenu dans ../mirror/"${tgt%% .*}"et celui référencé par se ./' 'réfèrent au même fichier. Ils décrivent le même fichier. Ils le nomment, mais rien de plus. Il n'y a pas de mystère, vraiment, juste quelques inconvénients que vous pourriez vous faire, mais qui auront finalement peu ou pas d'effet sur le fonctionnement de votre système de fichiers Unix à la fin.

Mikeserv
la source