44 votes

Pourquoi ne bash echo [t]" résultat en "t" et non pas "[t]"

Ce qui se passe pour le personnage de t, et la valeur de la racine. Assez déroutant

$ echo [s]
[s]
$ echo [t]
t
$ echo [ t ]
[ t ]
$ echo [root]
t

62voto

devnull Points 45016

[] désigne une classe de personnage et que vous avez un fichier nommé t dans votre répertoire courant.

Les éléments suivants doivent l'expliquer plus loin:

$ ls
$ echo [t]
[t]
$ touch t
$ echo [t]
t
$ echo [root]
t
$ touch r
$ echo [root]
r t

Si vous voulez changer quelque chose dans [], d'échapper à la [:

echo \[$var]

Observer la différence maintenant:

$ echo \[root]
[root]

ou, comme Glenn Jackman souligne le citer:

$ echo '[root]'
[root]
$ echo "[root]"
[root]

Shell Langage de Commande indique que les caractères suivants sont spéciaux pour le shell selon le contexte:

*   ?   [   #   ~   =   %

En outre, les caractères suivants doivent être indiqués s'ils sont à se représenter eux-mêmes:

|  &  ;  <  >  (  )  $  `  \  "  '  <space>  <tab>  <newline>

Vous pouvez également utiliser printf afin de déterminer quels sont les personnages dans une entrée donnée doivent être échappé si vous n'êtes pas en citant les arguments. Pour ton exemple, c'est à dire [s]:

$ printf "%q" "[s]"
\[s\]

Un autre exemple:

$ printf "%q" "[0-9]|[a-z]|.*?$|1<2>3|(foo)"
\[0-9\]\|\[a-z\]\|.\*\?\$\|1\<2\>3\|\(foo\)

26voto

Amal Murali Points 37729

[] dénote un caractère de classe. Il suffit de mettre, une classe de caractères est une façon de définir un ensemble de caractères de telle manière qu' un personnage de la série est mis en correspondance. [A-Z] est un très bon exemple -, il correspond à tous les alphabets d' A par Z.

Voici les résultats des commandes dans un nouveau répertoire:

$ echo [s]
[s]
$ echo [t]
[t]
$ echo [ t ]
[ t ]
$ echo [root]
[root]

Comme vous pouvez le voir, echo affiché comme il est. Pourquoi? Lisez la section suivante.

L'Expansion

Chaque fois que vous tapez une commande dans le Terminal et appuyez sur la touche ENTRÉE, bash effectue beaucoup d'activités à l'interne avant de les imprimer les résultats de la coquille. L'exemple le plus simple est l'expansion de l' *:

$ echo *
evil_plans.txt dir1 dir2

Au lieu d'afficher le littéral * de toute la production, de l'imprimer le contenu du répertoire. Pourquoi est-ce arrivé? Parce qu' * a une signification particulière - c'est un générique, qui peut correspondre à n'importe quel caractère du nom de fichier. Il est important de noter que l' echo commande ne permet pas de voir l' * - dont seulement le résultat développé.

Il existe différents types d'expansions:

  • Attelle d'extension
  • Tilde expansion
  • Paramètre d'extension
  • Commande d'extension
  • L'expansion arithmétique
  • Processus de substitution
  • Expansion de nom de fichier

... et probablement plus. Dans ce cas, l'expansion de nom de fichier est le type de l'expansion.

Expansion de nom de fichier

Lorsque vous tapez un echo commande et appuyez sur ENTRÉE, bash processus de la commande et la divise en mots. Une fois que c'est fait, il analyse les mots pour les caractères suivants: ?, * et [. Tous ces éléments sont des caractères de remplacement et ont une signification spéciale. Si bash trouve une occurrence de l'un de ces caractères, il traite les mots fourni comme modèle.

Par exemple, considérons le cas suivant:

$ touch foobar foobak fooqux barbar boofar
$ echo foo*
foobar foobak fooqux

Comme vous pouvez le voir, l' * élargi et dressé la liste de correspondance des noms de fichier. (Dans ce cas, ceux qui commencent par foo.)

Maintenant, nous allons essayer un autre exemple:

$ touch gray.txt grey.txt
$ echo gr?y.txt
gray.txt grey.txt

? correspond à un caractère unique. Rien de plus. Dans ce cas, gray.txt et grey.txt à la fois correspond au motif, de sorte que les deux ont été imprimés.

Un autre exemple:

$ touch hello hullo hallo
$ echo h[aeu]llo
hallo hello hullo

Ce qui s'est passé ici? Comme vous le savez, partir de avant la, [aeu] est une classe de caractères. Une classe de caractères correspond exactement à l'un des personnages; il ne correspond jamais avec plus d'un caractère. Dans ce cas, les caractères de la classe de personnage pouvait correspondre les noms de fichiers correctement, de sorte que les résultats ont été imprimés.

Si aucune correspondance des noms de fichier est trouvé, le mot est laissé inchangé.

Explication pour votre cas spécifique

$ echo [s]

[s] est une classe de personnage et il correspond à un seul caractère - un littéral s. Mais pas les fichiers correspondants ont été trouvés, de sorte qu'il a été retourné comme il est.

$ echo [t]

[t] est une classe de personnage ainsi. Il correspond à un seul caractère. Il y a un fichier nommé t dans votre répertoire, sens il y avait un match. Donc, il est rentré de trouver le nom du nom de fichier.

$ echo [root]

[root] correspond aux caractères suivants: r, o, t. Comme vous l'avez probablement deviné, o se produisant deux fois dans la classe de caractères n'est pas de faire une différence ici. Une classe de caractères ne peuvent correspondre à un seul caractère. Donc, echo [root] vous essayez de trouver les noms de fichier qui a un caractère correspondant. Depuis un fichier nommé t il existe dans votre répertoire, il est listé ci.

Comment éviter ce genre de bizarreries?

Toujours utiliser de devis et de s'échapper en cas de besoin. Ils vous donnent un contrôle général sur l'analyse, l'extension et l'expansion des résultats.

14voto

Raffaele Points 10209

N'étant pas un shell habitué (et pas disposés à le devenir), je l'ai trouvé surprenant de constater que le nom de fichier d'extension est conçu pour se comporter lorsqu'aucune correspondance n'est trouvée. Je vais signaler le Bash de référence

Bash analyse chaque mot pour les personnages *, ?, et [. Si l'un des ces caractères s'affiche, puis le mot est considéré comme un modèle, et remplacée par une liste triée par ordre alphabétique des noms de fichiers correspondant à la de modèle. Si aucun fichier de correspondance des noms sont:

  • si l'option shell nullglob est désactivé, le mot est resté inchangé
  • si l'option shell nullglob est de définir le mot est supprimé
  • Si l' failglob coque option est activée, un message d'erreur est imprimé et la commande n'est pas exécutée

La bonne nouvelle, c'est que cette chose est configurable. La mauvaise est un script peut échouer dans un certain nombre de façons on n'en attend pas - au moins, je n'ai pas, et il m'a fallu un certain temps pour comprendre pourquoi echo se comporte de la façon que vous avez posté, juste pour trouver que c'est en raison d'une combinaison de bizarre les noms de fichiers (qui ne veut jamais le nom d'un fichier t?), configuration cachée (nullglob désactivé, option par défaut, mais encore cachés) et un inoffensif commande.

Je l'ai dit inoffensif parce que c'est ce que vous obtenez, par exemple, lorsque la cible est - ls (un échec parce que le fichier n'est pas trouvé):

raffaele@Aldebaran:~$ mkdir test
raffaele@Aldebaran:~$ cd test
raffaele@Aldebaran:~/test$ touch t
raffaele@Aldebaran:~/test$ ls [t]
t
raffaele@Aldebaran:~/test$ ls [v]
ls: cannot access [v]: No such file or directory

9voto

mklement0 Points 12597

Pour compléter @devnull de réponse utile:

À l'aide d'un non-cotées chaîne dans bash (dans la plupart des cas) fait être interprétée comme un modèle (expression générique; grosso modo, un lointain, primitif par rapport à une expression régulière).

Dans votre cas, le modèle est mis en correspondance avec les noms des fichiers et sous-dossiers dans le dossier de travail en cours, comme @devnull montre: [root] moyen: match de n'importe quel fichier dont le nom se compose de seulement 1 personnage qui est soit r ou o (en précisant o deux fois, c'est redondant) ou t. Cette mise en correspondance d'un modèle sur les noms de fichiers est appelé nom de chemin d'expansion.

Notez qu'il s'applique également aux sociétés non cotées références à des variables, de sorte que les éléments suivants devraient donner le même résultat:

s='[t]'  # Assign string _literal_ (since quoted) to variable.
echo $s  # Content of $s, since unquoted, is now subject to pathname expansion.

Pour traiter une chaîne de caractères (sélectivement) littéralement, vous devez utiliser citant.

Il y a trois façons de citer les chaînes en bash, à l'aide de votre exemple:


\- citer les différents caractères qui ont une signification particulière (soi-disant caractères de remplacement):

echo \[t\]

Cela garantit que ces caractères spéciaux sont traités comme des littéraux.


Placer la chaîne entre guillemets simples ('...'):

echo '[t]'

Ce protège la chaîne de toutes les expansions (interprétation) par le shell.
Mise en garde: vous ne pouvez pas inclure un ' lui-même dans une seule chaîne de caractères entre guillemets (même pas à l'échappement).


Placer la chaîne à guillemets doubles ("..."):

echo "[t]"

Cela protège la chaîne à partir de certains des expansions par le shell, bien que de manière sélective en permettant à d'autres.

En l'espèce, '[t]' et "[t]" se comportent de façon identique.

Cependant, l'utilisation de l' " vous permet de faire référence à des variables et d'effectuer des substitutions de commande l'intérieur de la chaîne, par exemple:

echo "Home, sweet $HOME." # reference to variable $HOME

echo "Today's date and the current time are: $(date)" # command substitution

Pour une liste de tous les travaux d'agrandissement effectués par bash, de recherche pour la section EXPANSION en man bash.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X