Comment échapper à des guillemets simples dans des chaînes de guillemets simples?
disons, vous avez un bash alias
comme:
alias rxvt='urxvt'
qui fonctionne très bien.
cependant:
alias rxvt='urxvt -fg '#111111' -bg '#111111''
ne fonctionne pas, ni:
alias rxvt='urxvt -fg '#111111' -bg '#111111''
alors comment se fait-il que vous finissiez par faire correspondre l'ouverture et la fermeture des guillemets à l'intérieur d'une chaîne une fois que vous avez échappé aux guillemets?
alias rxvt='urxvt -fg'''#111111''' -bg '''#111111'''
semble ungainly bien qu'il représenterait la même chaîne si vous êtes autorisé pour les concaténer comme ça.
19 réponses
si vous voulez vraiment utiliser des guillemets simples dans la couche la plus externe, rappelez-vous que vous pouvez coller les deux types de guillemets. Exemple:
alias rxvt='urxvt -fg '"'"'#111111'"'"' -bg '"'"'#111111'"'"
# ^^^^^ ^^^^^ ^^^^^ ^^^^
# 12345 12345 12345 1234
explication de la façon dont '"'"'
est interprété comme juste '
:
-
'
fin de la première citation qui utilise des guillemets simples. -
"
commencer la deuxième citation, en utilisant des doubles citations. -
'
Cité caractère. -
"
fin de la deuxième citation, en utilisant des guillemets. -
'
lancer la troisième Cotation, en utilisant des guillemets simples.
si vous ne placez aucun espace blanc entre (1) et (2), ou entre (4) et (5), le shell interprétera cette chaîne comme un long mot.
je remplace toujours chaque citation unique intégrée par la séquence: '\''
(c'est-à-dire: citation de backslash citation) qui ferme la chaîne, ajoute une citation unique échappée et rouvre la chaîne.
j'ai souvent créé une fonction "quotify" dans mes scripts Perl pour le faire à ma place. Les étapes seraient les suivantes:
s/'/'\''/g # Handle each embedded quote
$_ = qq['$_']; # Surround result with single quotes.
ça règle Tous les cas.
la Vie devient plus amusant lorsque vous introduisez eval
dans vos scripts shell. Vous devez essentiellement tout re-quotifier à nouveau!
par exemple, créer un script Perl appelé quotify contenant les déclarations ci-dessus:
#!/usr/bin/perl -pl
s/'/'\''/g;
$_ = qq['$_'];
puis l'utiliser pour générer une chaîne correctement Citée:
$ quotify
urxvt -fg '#111111' -bg '#111111'
résultat:
'urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''
, qui peut ensuite être copié/collé dans la commande alias:
alias rxvt='urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''
(si vous avez besoin d'insérer la commande dans une eval, relancez la commande quotify:
$ quotify
alias rxvt='urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''
résultat:
'alias rxvt='\''urxvt -fg '\''\'\'''\''#111111'\''\'\'''\'' -bg '\''\'\'''\''#111111'\''\'\'''\'''\'''
qui peut être copié/collé dans une évaluation:
eval 'alias rxvt='\''urxvt -fg '\''\'\'''\''#111111'\''\'\'''\'' -bg '\''\'\'''\''#111111'\''\'\'''\'''\'''
depuis Bash 2.04 syntaxe $'string'
(au lieu de juste 'string'
; AVERTISSEMENT: Ne pas confondre avec $('string')
) est un autre mécanisme de citation qui permet ANSI C-like escape sequences et faire l'expansion à la version simple-Cité.
exemple Simple:
$> echo $'aa\'bb'
aa'bb
$> alias myvar=$'aa\'bb'
$> alias myvar
alias myvar='aa'\''bb'
dans votre cas:
$> alias rxvt=$'urxvt -fg \'#111111\' -bg \'#111111\''
$> alias rxvt
alias rxvt='urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''
Commune échapper séquences fonctionne comme prévu:
\' single quote
\" double quote
\ backslash
\n new line
\t horizontal tab
\r carriage return
ci-Dessous est la copie+collé documents connexes à partir de man bash
(version 4.4):
les mots de la forme $'string' sont traités spécialement. Le mot se développe en string, les caractères échappés par backslash étant remplacés comme spécifié par la norme ANSI C. Les séquences d'échappement de Backlash, si elles sont présentes, sont décodées comme suit:
\a alert (bell)
\b backspace
\e
\E an escape character
\f form feed
\n new line
\r carriage return
\t horizontal tab
\v vertical tab
\ backslash
\' single quote
\" double quote
\? question mark
\nnn the eight-bit character whose value is the octal
value nnn (one to three digits)
\xHH the eight-bit character whose value is the hexadecimal
value HH (one or two hex digits)
\uHHHH the Unicode (ISO/IEC 10646) character whose value is
the hexadecimal value HHHH (one to four hex digits)
\UHHHHHHHH the Unicode (ISO/IEC 10646) character whose value
is the hexadecimal value HHHHHHHH (one to eight
hex digits)
\cx a control-x character
le résultat élargi est mono-coté, comme si le signe de dollar avait pas été présent.
Voir Citations et d'évasion: ANSI C comme les chaînes de caractères bash-hackers.org wiki pour plus de détails. Notez également que "Bash Changes" fichier ( vue d'ensemble ici ) mentionne beaucoup de changements et de corrections de bugs liés au mécanisme de citation $'string'
.
, Selon unix.stackexchange.com Comment utiliser un caractère spécial un normal? cela devrait fonctionner (avec quelques variantes) avec bash, zsh, mksh, ksh93 et FreeBSD et busybox sh.
je ne vois pas l'entrée sur son blog (lien pls?), mais selon le gnu " manuel de référence de :
contenant des caractères entre guillemets (‘’) préserve la valeur littérale de chaque caractère entre les guillemets. Un une seule citation ne peut pas se produire entre des guillemets simples, même précédés d'un oblique.
pour que bash ne comprenne pas:
alias x='y \'z '
cependant, vous pouvez le faire si vous entourez de doubles guillemets:
alias x="echo \'y "
> x
> 'y
je peux confirmer que l'utilisation de '\''
pour une seule citation à l'intérieur d'une chaîne de caractères à une seule citation fonctionne dans Bash, et il peut être expliqué de la même manière que l'argument" collage " de plus tôt dans le fil. Supposons que nous ayons une chaîne de caractères Citée: 'A '\''B'\'' C'
(toutes les citations ici sont des citations simples). Si elle est transmise à echo, elle imprime ce qui suit: A 'B' C
.
Dans chaque '\''
la première citation ferme la chaîne actuelle de citation simple, le suivant \'
colle une citation simple à la la chaîne précédente ( \'
est une façon de spécifier une seule citation sans démarrer une chaîne Citée), et la dernière citation ouvre une autre chaîne Citée.
exemple Simple d'échapper les guillemets dans l'enveloppe:
$ echo 'abc'\''abc'
abc'abc
$ echo "abc"\""abc"
abc"abc
il est fait en finissant déjà ouvert un ( '
), en plaçant échappé un ( \'
), puis en ouvrant un autre ( '
). Cette syntaxe fonctionne pour toutes les commandes. C'est une approche très similaire à la première réponse.
Je n'aborde pas spécifiquement la question des citations parce que, bien, parfois, il est juste raisonnable d'envisager une approche alternative.
rxvt() { urxvt -fg "#${1:-000000}" -bg "#${2:-FFFFFF}"; }
que vous pouvez alors appeler:
rxvt 123456 654321
l'idée étant que vous pouvez maintenant alias sans préoccupation pour les citations:
alias rxvt='rxvt 123456 654321'
ou, si vous devez inclure le #
dans tous les appels pour une raison quelconque:
rxvt() { urxvt -fg "${1:-#000000}" -bg "${2:-#FFFFFF}"; }
qui vous pouvez alors appeler comme:
rxvt '#123456' '#654321'
alors, bien sûr, un alias est:
alias rxvt="rxvt '#123456' '#654321'"
(oups, je suppose que je n'adresse la citation :)
j'utilise juste des codes shell.. par exemple \x27
ou \x22
selon le cas. Pas de soucis, jamais vraiment.
Puisqu'on ne peut pas mettre de guillemets simples dans des chaînes de guillemets simples, l'option la plus simple et la plus lisible est D'utiliser une chaîne HEREDOC
command=$(cat <<'COMMAND'
urxvt -fg '#111111' -bg '#111111'
COMMAND
)
alias rxvt=$command
dans le code ci-dessus, L'HÉRÉDOC est envoyé à la commande cat
et la sortie de celle-ci est assignée à une variable via la notation de substitution de commande $(..)
mettre une seule citation autour de L'HEREDOC est nécessaire car il est dans un $()
les deux versions fonctionnent, soit avec concaténation en utilisant le caractère de citation unique échappé (\'), soit avec concaténation en enfermant le caractère de citation unique dans des guillemets doubles ("'").
l'auteur de la question n'a pas remarqué qu'il y avait une citation supplémentaire (') à la fin de sa dernière tentative d'évasion:
alias rxvt='urxvt -fg'\''#111111'\'' -bg '\''#111111'\''
│ │┊┊| │┊┊│ │┊┊│ │┊┊│
└─STRING──┘┊┊└─STRIN─┘┊┊└─STR─┘┊┊└─STRIN─┘┊┊│
┊┊ ┊┊ ┊┊ ┊┊│
┊┊ ┊┊ ┊┊ ┊┊│
└┴─────────┴┴───┰───┴┴─────────┴┘│
All escaped single quotes │
│
?
comme vous pouvez le voir dans le précédent beau morceau D'ASCII / Unicode art, la dernière citation unique échappée (\') est suivie d'une citation unique Inutile ('). L'utilisation d'un surligneur de syntaxe comme celui présent dans Notepad++ peut s'avérer très utile.
la même chose est vraie pour un autre exemple comme le suivant:
alias rc='sed '"'"':a;N;$!ba;s/\n/, /g'"'"
alias rc='sed '\'':a;N;$!ba;s/\n/, /g'\'
ces deux belles occurrences d'alias montrent d'une manière très complexe et confuse comment un fichier peut être aligné vers le bas. C'est, à partir d'un fichier avec beaucoup de lignes que vous obtenez une seule ligne avec des virgules et des espaces entre le contenu de l' lignes précédentes. Afin de connaître le sens du commentaire précédent, voici un exemple:
$ cat Little_Commas.TXT
201737194
201802699
201835214
$ rc Little_Commas.TXT
201737194, 201802699, 201835214
IMHO la vraie réponse est que vous ne pouvez pas échapper à des guillemets simples.
c'est impossible.
si nous supposons que nous utilisons bash.
du manuel de bash...
Enclosing characters in single quotes preserves the literal value of each
character within the quotes. A single quote may not occur
between single quotes, even when preceded by a backslash.
vous devez utiliser l'un des autres mécanismes d'échappement de chaîne de caractères "ou \
il n'y a rien de magique dans alias
qui exige qu'il utilise des guillemets simples.
Les deux travaux suivants à bash.
alias rxvt="urxvt -fg '#111111' -bg '#111111'"
alias rxvt=urxvt\ -fg\ \'#111111\'\ -bg\ \'#111111\'
ce dernier utilise \ pour échapper au caractère d'espace.
il n'y a rien de magique non plus au #111111 qui nécessite des guillemets simples.
les options suivantes atteignent le même résultat que les deux autres options, en ce que l'alias rxvt fonctionne comme prévu.
alias rxvt='urxvt -fg "#111111" -bg "#111111"'
alias rxvt="urxvt -fg \"#111111\" -bg \"#111111\""
, Vous pouvez aussi échapper à l'importun # directement
alias rxvt="urxvt -fg \#111111 -bg \#111111"
la plupart de ces réponses correspondent au cas précis que vous cherchez. Il y a une approche générale qu'un ami et moi avons développée qui permet de citer arbitrairement au cas où vous auriez besoin de citer des commandes bash à travers plusieurs couches d'extension de shell, par exemple, à travers ssh, su -c
, bash -c
, etc. Il y a une primitive de base dont vous avez besoin, ici à native bash:
quote_args() {
local sq="'"
local dq='"'
local space=""
local arg
for arg; do
echo -n "$space'${arg//$sq/$sq$dq$sq$dq$sq}'"
space=" "
done
}
Cela fait exactement ce qu'il dit: il shell-cite chaque argument individuellement (après l'expansion de bash, bien sûr):
$ quote_args foo bar
'foo' 'bar'
$ quote_args arg1 'arg2 arg2a' arg3
'arg1' 'arg2 arg2a' 'arg3'
$ quote_args dq'"'
'dq"'
$ quote_args dq'"' sq"'"
'dq"' 'sq'"'"''
$ quote_args "*"
'*'
$ quote_args /b*
'/bin' '/boot'
Il ne la chose la plus évidente pour une couche d'expansion:
$ bash -c "$(quote_args echo a'"'b"'"c arg2)"
a"b'c arg2
(notez que les doubles guillemets autour de $(quote_args ...)
sont nécessaires pour faire le résultat en un seul argument à bash -c
.) Et il peut être utilisé plus généralement pour citer correctement à travers plusieurs couches d'expansion:
$ bash -c "$(quote_args bash -c "$(quote_args echo a'"'b"'"c arg2)")"
a"b'c arg2
l'exemple ci-dessus:
- shell-cite chaque argument à l'intérieur
quote_args
individuellement et puis combine la Sortie Résultant en un seul argument avec les doubles guillemets intérieurs. - shell-guillemets
bash
,-c
, et le déjà une fois-cité résultat de l'étape 1, puis combine le résultat en un seul argument avec les doubles guillemets externes. - envoie ce mess comme argument à l'extérieur
bash -c
.
C'est l'idée en un mot. Vous pouvez faire des choses assez compliquées avec cela, mais vous devez faire attention à l'ordre de l'évaluation et à propos de Quels substrats sont cités. Par exemple, ce qui suit font les mauvaises choses (pour une certaine définition de "mal"):
$ (cd /tmp; bash -c "$(quote_args cd /; pwd 1>&2)")
/tmp
$ (cd /tmp; bash -c "$(quote_args cd /; [ -e *sbin ] && echo success 1>&2 || echo failure 1>&2)")
failure
dans le premier exemple, bash étend immédiatement quote_args cd /; pwd 1>&2
en deux commandes séparées, quote_args cd /
et pwd 1>&2
, de sorte que le CWD est toujours /tmp
lorsque le pwd
la commande est exécutée. Le deuxième exemple illustre un problème similaire pour l'expansion. En effet, le même problème de base se produit avec toutes les expansions de bash. Le problème ici est qu'une substitution de commande n'est pas un appel de fonction: elle évalue littéralement un script bash et utilise sa sortie comme partie d'un autre script bash.
si vous essayez simplement d'échapper aux opérateurs shell, vous échouerez parce que la chaîne résultante passée à bash -c
est juste une séquence de les chaînes citées individuellement qui ne sont pas alors interprétées comme des opérateurs, ce qui est facile à voir si vous faites écho à la chaîne qui aurait été passée à bash:
$ (cd /tmp; echo "$(quote_args cd /\; pwd 1\>\&2)")
'cd' '/;' 'pwd' '1>&2'
$ (cd /tmp; echo "$(quote_args cd /\; \[ -e \*sbin \] \&\& echo success 1\>\&2 \|\| echo failure 1\>\&2)")
'cd' '/;' '[' '-e' '*sbin' ']' '&&' 'echo' 'success' '1>&2' '||' 'echo' 'failure' '1>&2'
le problème, c'est que vous citez trop. Ce qu'il faut , c'est que les opérateurs ne soient pas cités comme entrées dans l'enveloppe bash -c
, ce qui signifie qu'ils doivent être en dehors de la substitution de commande $(quote_args ...)
.
par conséquent, ce que vous devez faire dans le plus général sens est de citer chaque mot de la commande qui n'est pas destiné à être étendu au moment de la substitution de commande séparément, et ne pas appliquer de citation supplémentaire aux opérateurs de shell:
$ (cd /tmp; echo "$(quote_args cd /); $(quote_args pwd) 1>&2")
'cd' '/'; 'pwd' 1>&2
$ (cd /tmp; bash -c "$(quote_args cd /); $(quote_args pwd) 1>&2")
/
$ (cd /tmp; echo "$(quote_args cd /); [ -e *$(quote_args sbin) ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")
'cd' '/'; [ -e *'sbin' ] && 'echo' 'success' 1>&2 || 'echo' 'failure' 1>&2
$ (cd /tmp; bash -c "$(quote_args cd /); [ -e *$(quote_args sbin) ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")
success
une fois que vous avez fait ceci, la chaîne entière est un jeu juste pour citer davantage à des niveaux arbitraires d'évaluation:
$ bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); $(quote_args pwd) 1>&2")"
/
$ bash -c "$(quote_args bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); $(quote_args pwd) 1>&2")")"
/
$ bash -c "$(quote_args bash -c "$(quote_args bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); $(quote_args pwd) 1>&2")")")"
/
$ bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); [ -e *$(quote_args sbin) ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")"
success
$ bash -c "$(quote_args bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); [ -e *sbin ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")")"
success
$ bash -c "$(quote_args bash -c "$(quote_args bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); [ -e *$(quote_args sbin) ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")")")"
success
etc.
ces exemples peuvent sembler exagérés étant donné que des mots comme success
, sbin
, et pwd
n'ont pas besoin d'être cités par shell, mais le point clé à se rappeler lors de l'écriture d'un script en prenant une entrée arbitraire est que vous voulez citer tout ce que vous n'êtes pas absolument sûr n'a pas besoin de citer, parce que vous ne savez jamais quand un utilisateur va jeter dans un Robert'; rm -rf /
.
pour mieux comprendre ce qui se passe sous les couvertures, vous pouvez jouer avec deux petites fonctions d'aide:
debug_args() {
for (( I=1; $I <= $#; I++ )); do
echo -n "$I:<${!I}> " 1>&2
done
echo 1>&2
}
debug_args_and_run() {
debug_args "$@"
"$@"
}
qui énumérera chaque argument à une commande avant de l'exécuter:
$ debug_args_and_run echo a'"'b"'"c arg2
1:<echo> 2:<a"b'c> 3:<arg2>
a"b'c arg2
$ bash -c "$(quote_args debug_args_and_run echo a'"'b"'"c arg2)"
1:<echo> 2:<a"b'c> 3:<arg2>
a"b'c arg2
$ bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run echo a'"'b"'"c arg2)")"
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'echo' 'a"b'"'"'c' 'arg2'>
1:<echo> 2:<a"b'c> 3:<arg2>
a"b'c arg2
$ bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run echo a'"'b"'"c arg2)")")"
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'bash' '-c' ''"'"'debug_args_and_run'"'"' '"'"'echo'"'"' '"'"'a"b'"'"'"'"'"'"'"'"'c'"'"' '"'"'arg2'"'"''>
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'echo' 'a"b'"'"'c' 'arg2'>
1:<echo> 2:<a"b'c> 3:<arg2>
a"b'c arg2
$ bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run echo a'"'b"'"c arg2)")")")"
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'bash' '-c' ''"'"'debug_args_and_run'"'"' '"'"'bash'"'"' '"'"'-c'"'"' '"'"''"'"'"'"'"'"'"'"'debug_args_and_run'"'"'"'"'"'"'"'"' '"'"'"'"'"'"'"'"'echo'"'"'"'"'"'"'"'"' '"'"'"'"'"'"'"'"'a"b'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'c'"'"'"'"'"'"'"'"' '"'"'"'"'"'"'"'"'arg2'"'"'"'"'"'"'"'"''"'"''>
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'bash' '-c' ''"'"'debug_args_and_run'"'"' '"'"'echo'"'"' '"'"'a"b'"'"'"'"'"'"'"'"'c'"'"' '"'"'arg2'"'"''>
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'echo' 'a"b'"'"'c' 'arg2'>
1:<echo> 2:<a"b'c> 3:<arg2>
a"b'c arg2
dans l'exemple donné, utilisé simplement des guillemets doubles au lieu de guillemets simples comme mécanisme d'échappement externe:
alias rxvt="urxvt -fg '#111111' -bg '#111111'"
cette approche est appropriée pour de nombreux cas où vous voulez simplement passer une chaîne fixe à une commande: vérifiez juste comment le shell interprétera la chaîne double-Citée à travers un echo
, et échappez les caractères avec antislash si nécessaire.
Dans l'exemple, vous verriez que les guillemets sont suffisantes pour protéger la chaîne de caractères:
$ echo "urxvt -fg '#111111' -bg '#111111'"
urxvt -fg '#111111' -bg '#111111'
voici une explication sur la seule vraie réponse mentionnée ci-dessus:
Parfois je vais télécharger en utilisant rsync sur ssh et je dois échapper à un nom de fichier avec un ' dedans deux fois! (OMG!) Une fois pour bash et une fois pour ssh. Le même principe d'alternance des délimiteurs de cotation est à l'œuvre ici.
par exemple, disons que nous voulons obtenir: la Stories de Louis Theroux ...
- d'abord vous enfermez Louis Theroux dans guillemets simples pour bash et guillemets doubles pour ssh: ""Louis Theroux "
- ensuite, vous utilisez des guillemets simples pour échapper à une double citation '"
- l'utilisation de doubles guillemets pour échapper à l'apostrophe "'
- puis répéter #2, en utilisant des guillemets simples pour échapper à une double citation '"
- puis inclure les histoires de LA dans des guillemets simples pour bash et des guillemets doubles pour ssh:'" la Stories "'
et voici! Vous vent en haut avec ceci:
rsync -ave ssh '"Louis Theroux"''"'"'"'"''"s LA Stories"'
qui est beaucoup de travail pour un peu " -- mais là, vous allez
une autre façon de résoudre le problème de trop de couches de citations emboîtées:
Vous essayez de caser trop trop petit espace, alors utiliser une fonction bash.
le problème est que vous essayez d'avoir trop de niveaux de nidification, et la technologie alias de base n'est pas assez puissante pour accommoder. Utilisez une fonction de bash comme celle-ci pour faire en sorte que les simples, doubles guillemets retour et passés dans les paramètres sont tous
lets_do_some_stuff() {
tmp= #keep a passed in parameter.
run_your_program $@ #use all your passed parameters.
echo -e '\n-------------' #use your single quotes.
echo `date` #use your back ticks.
echo -e "\n-------------" #use your double quotes.
}
alias foobarbaz=lets_do_some_stuff
alors vous pouvez utiliser vos variables $1 et $2 et les simples, doubles guillemets et coups de pied arrière sans vous soucier de la fonction d'alias ruinant leur intégrité.
ce programme imprime:
el@defiant ~/code $ foobarbaz alien Dyson ring detected @grid 10385
alien Dyson ring detected @grid 10385
-------------
Mon Oct 26 20:30:14 EDT 2015
-------------
cette fonction:
quote ()
{
local quoted=${1//\'/\'\\'\'};
printf "'%s'" "$quoted"
}
permet de citer '
à l'intérieur de '
. Comme ceci:
$ quote "urxvt -fg '#111111' -bg '#111111'"
'urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''
si la ligne à citer devient plus complexe, comme les doubles guillemets mélangés avec des guillemets simples, il peut devenir très difficile d'obtenir la chaîne à citer à l'intérieur d'une variable. Lorsque de tels cas apparaissent, écrivez la ligne exacte que vous devez citer dans un script (similaire à celui-ci).
#!/bin/bash
quote ()
{
local quoted=${1//\'/\'\\'\'};
printf "'%s'" "$quoted"
}
while read line; do
quote "$line"
done <<-\_lines_to_quote_
urxvt -fg '#111111' -bg '#111111'
Louis Theroux's LA Stories
'single quote phrase' "double quote phrase"
_lines_to_quote_
sortira:
'urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''
'Louis Theroux'\''s LA Stories'
''\''single quote phrase'\'' "double quote phrase"'
toutes les chaînes correctement citées entre guillemets simples.
Évidemment, il serait plus facile de simplement entourer de guillemets, mais où est le problème? Voici la réponse en utilisant uniquement des guillemets simples. J'utilise une variable au lieu de alias
donc c'est plus facile à imprimer pour la preuve, mais c'est la même chose qu'utiliser alias
.
$ rxvt='urxvt -fg '\''#111111'\'' -bg '\''#111111'\'
$ echo $rxvt
urxvt -fg '#111111' -bg '#111111'
explication
la clé est que vous pouvez fermer le devis simple et le rouvrir autant de fois que vous voulez. Pour exemple foo='a''b'
est le même que foo='ab'
. Donc vous pouvez fermer la citation simple , jeter dans une citation simple littérale \'
, puis rouvrir la citation simple suivante.
ce diagramme le montre clairement en utilisant des crochets pour indiquer où les guillemets simples sont ouverts et fermés. Les guillemets ne sont pas" imbriqués " comme les parenthèses peuvent l'être. Vous pouvez également faire attention à la mise en évidence des couleurs, qui est correctement appliquer. Les cordes citées sont marron, tandis que le \'
est noir.
'urxvt -fg '\''#111111'\'' -bg '\''#111111'\' # original
[^^^^^^^^^^] ^[^^^^^^^] ^[^^^^^] ^[^^^^^^^] ^ # show open/close quotes
urxvt -fg ' #111111 ' -bg ' #111111 ' # literal characters remaining
(c'est essentiellement la même réponse que celle d'Adrian, mais je pense que cela explique mieux. Aussi sa réponse a 2 citations simples superflues à la fin.)
Voici une autre solution. Cette fonction prend un seul argument et le cite correctement en utilisant le caractère de citation simple, tout comme la réponse votée ci-dessus explique:
single_quote() {
local quoted="'"
local i=0
while [ $i -lt ${#1} ]; do
local ch="${1:i:1}"
if [[ "$ch" != "'" ]]; then
quoted="$quoted$ch"
else
local single_quotes="'"
local j=1
while [ $j -lt ${#1} ] && [[ "${1:i+j:1}" == "'" ]]; do
single_quotes="$single_quotes'"
((j++))
done
quoted="$quoted'\"$single_quotes\"'"
((i+=j-1))
fi
((i++))
done
echo "$quoted'"
}
ainsi, vous pouvez l'utiliser de cette façon:
single_quote "1 2 '3'"
'1 2 '"'"'3'"'"''
x="this text is quoted: 'hello'"
eval "echo $(single_quote "$x")"
this text is quoted: 'hello'
si vous générez la chaîne shell dans Python 2 ou Python 3, ce qui suit peut aider à citer les arguments:
#!/usr/bin/env python
from __future__ import print_function
try: # py3
from shlex import quote as shlex_quote
except ImportError: # py2
from pipes import quote as shlex_quote
s = """foo ain't "bad" so there!"""
print(s)
print(" ".join([shlex_quote(t) for t in s.split()]))
cette sortie:
foo ain't "bad" so there!
foo 'ain'"'"'t' '"bad"' so 'there!'