La echo
commande n'inclut pas le texte complet que je lui donne. Par exemple, si je le fais:
$ echo ' echo PARAM=` grep $ARG /var/tmp/setfile | awk '{print $2}' ` '
Il génère:
echo PARAM=` grep $ARG /var/tmp/setfile | awk {print } `
Les guillemets simples ( '
) que j'avais dans ma commande echo ne sont pas inclus. Si je passe aux guillemets doubles:
$ echo " echo PARAM=` grep $ARG /var/tmp/setfile | awk '{print $2}' ` "
echo
ne produit rien du tout! Pourquoi oublie-t-il les guillemets simples dans le premier exemple et ne produit-il rien dans le second? Comment puis-je le faire sortir exactement ce que j'ai tapé?
Réponses:
Votre shell interprète les guillemets, à la fois
'
et"
, avant même qu'ils ne parviennent àecho
. Je mets généralement des guillemets autour de mon argument pour faire écho même s'ils ne sont pas nécessaires; par exemple:Ainsi, dans votre premier exemple, si vous souhaitez inclure des guillemets littéraux dans votre sortie, vous devez soit les échapper:
Ou ils doivent déjà être utilisés dans un argument cité (mais ce ne peut pas être le même type de citation, ou vous devrez quand même y échapper):
Dans votre deuxième exemple, vous exécutez une substitution de commande au milieu de la chaîne:
Les choses qui commencent par
$
sont également gérées spécialement par le shell - il les traite comme des variables et les remplace par leurs valeurs. Étant donné que très probablement aucune de ces variables n'est définie dans votre shell, il s'exécute simplementÉtant donné qu'il
grep
ne voit qu'un seul argument, il suppose que cet argument est le modèle que vous recherchez et que l'endroit où il doit lire les données est stdin, il bloque donc l'attente de l'entrée. C'est pourquoi votre deuxième commande semble se bloquer.Cela ne se produira pas si vous citez l'argument (ce qui explique pourquoi votre premier exemple a presque fonctionné), c'est donc une façon d'obtenir la sortie souhaitée:
Vous pouvez également le mettre entre guillemets, mais vous devrez ensuite échapper le
$
s pour que le shell ne les résout pas en tant que variables, et les astuces pour que le shell n'exécute pas immédiatement la substitution de commande:la source
Je ne vais pas entrer dans les détails pour expliquer pourquoi vos tentatives se comportent comme elles le font, car la réponse de Michael Mrozek couvre bien cela. En un mot, tout entre les guillemets simples (
'…'
) est interprété littéralement (et en particulier le premier'
marque la fin de la chaîne littérale), tandis que`
et$
conservent leur signification particulière entre"…"
.Il n'y a pas de guillemets dans les guillemets simples, vous ne pouvez donc pas mettre de guillemet simple dans une chaîne entre guillemets simples. Il existe cependant un idiome qui lui ressemble:
Cela s'imprime
foo'bar
, car l'argument toecho
est constitué de la chaîne de trois caractères entre guillemets simplesfoo
, concaténée avec le caractère unique'
(obtenue en protégeant le caractère'
de sa signification particulière par le biais du précédent\
), concaténée avec la chaîne de trois caractères entre guillemets simplesbar
. Donc, bien que ce ne soit pas tout à fait ce qui se passe dans les coulisses, vous pouvez penser'\''
à un moyen d'inclure une citation unique dans une chaîne entre guillemets simples.Si vous souhaitez imprimer des chaînes multilignes complexes, un meilleur outil est le document ici . Un document ici se compose des deux caractères
<<
suivis d'un marqueur tel que<<EOF
, puis de quelques lignes de texte, puis du marqueur de fin seul sur sa ligne. Si le marqueur est cité de quelque manière que ce soit ('EOF'
ou"EOF"
ou\EOF
ou 'E "" OF' ou…), alors le texte est interprété littéralement (comme à l'intérieur de guillemets simples, sauf que même'
est un caractère ordinaire). Si le marqueur n'est pas du tout cité, le texte est interprété comme dans une chaîne entre guillemets doubles, en$\`
conservant leur statut spécial (mais"
et les sauts de ligne sont interprétés littéralement).la source
D'accord, cela fonctionnera: -
Le tester ici: -
la source
La suggestion de Gilles d'utiliser un document ici est vraiment sympa, et fonctionne même dans des langages de script comme Perl. Comme exemple spécifique basé sur sa réponse à la question du PO,
Certes, cet exemple est un peu artificiel, mais j'ai trouvé que c'était une technique utile pour, disons, envoyer des instructions SQL à
psql
(au lieu decat
).(Notez que tout caractère non alphanumérique non espace peut être utilisé à la place de
#
dans la construction générique citée ci-dessus, mais le hachage semble bien ressortir pour cet exemple et n'est pas traité comme un commentaire.)la source
Prenons votre commande
et d'abord le diviser en mots, en utilisant un espace blanc sans guillemets comme délimiteur:
Ensuite, nous faisons l'expansion des paramètres: développez
$…
mais pas à l'intérieur'…'
. Puisque$2
est vide (sauf si vous le définissez via par exempleset -- …
), il sera remplacé par une chaîne vide.Ensuite, supprimez le devis.
Ces arguments sont ensuite passés à echo, qui les affichera l'un après l'autre, séparés par un seul espace.
J'espère que cette instruction étape par étape rend le comportement observé plus clair. Pour éviter le problème, échappez aux guillemets simples comme celui-ci:
Cela mettra fin à la chaîne entre guillemets simples, puis ajoutera un guillemet simple (échappé) au mot, puis démarrera une nouvelle chaîne entre guillemets simples, le tout sans séparer le mot.
la source