Question

Disons que 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, et ne le fera:

alias rxvt='urxvt -fg \'#111111\' -bg \'#111111\''

Alors, comment vous finissez par correspondance entre l'ouverture et la fermeture des guillemets à l'intérieur d'une chaîne, une fois que vous avez échappé d'un devis?

alias rxvt='urxvt -fg'\''#111111'\'' -bg '\''#111111'\''

semble anormale, bien que ce serait la même chaîne si vous êtes autorisés à les enchaîner comme ça.

Était-ce utile?

La solution

Si vous voulez vraiment utiliser des guillemets simples dans la couche la plus externe, rappelez-vous que vous pouvez coller les deux types de citation. Exemple:

 alias rxvt='urxvt -fg '"'"'#111111'"'"' -bg '"'"'#111111'"'"
 #                     ^^^^^       ^^^^^     ^^^^^       ^^^^
 #                     12345       12345     12345       1234

Explication de la façon dont '"'"' est interprété comme un simple ':

  1. ' Fin première citation qui utilise des guillemets simples.
  2. " Démarrer deuxième citation, en utilisant des guillemets doubles.
  3. ' caractère Quoted.
  4. Fin " deuxième citation, en utilisant des guillemets doubles.
  5. ' Démarrer troisième citation, en utilisant des guillemets simples.

Si vous ne placez pas entre espaces blancs (1) et (2), ou entre (4) et (5), le shell interprétera cette chaîne comme un long mot.

Autres conseils

Je toujours juste remplacer chaque guillemet simple intégré avec la séquence: '\'' (qui est: citation backslash citation citation) qui ferme la chaîne, ajoute un guillemet simple échappé et rouvre la chaîne.


Je fouette souvent une fonction « quotify » dans mes scripts Perl pour faire cela pour moi. Les étapes seraient:

s/'/'\\''/g    # Handle each embedded quote
$_ = qq['$_']; # Surround result with single quotes.

Cela prend à peu près soin de tous les cas.

La vie est plus amusant quand vous introduisez eval dans vos scripts shell. Vous avez essentiellement de re-quotify tout nouveau!

Par exemple, créer un script Perl appelé quotify contenant les déclarations ci-dessus:

#!/usr/bin/perl -pl
s/'/'\\''/g;
$_ = qq['$_'];

utilisez 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 alors être copier / coller dans la commande alias:

alias rxvt='urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''

(Si vous devez insérer la commande dans un eval, exécutez à nouveau le quotify:

 $ quotify
 alias rxvt='urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''

résultat:

'alias rxvt='\''urxvt -fg '\''\'\'''\''#111111'\''\'\'''\'' -bg '\''\'\'''\''#111111'\''\'\'''\'''\'''

qui peut être copier / coller dans un eval:

eval 'alias rxvt='\''urxvt -fg '\''\'\'''\''#111111'\''\'\'''\'' -bg '\''\'\'''\''#111111'\''\'\'''\'''\'''

Depuis Bash 2.04 la syntaxe $'string' (au lieu de simplement 'string';avertissement:ne pas confondre avec le $('string')) est un autre citant le mécanisme qui permet à C ANSI-comme les séquences d'échappement et faire de l'expansion à une seule cité de la version.

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ées spécialement.Le mot s'étend à la chaîne, avec une barre oblique inverse-des caractères d'échappement remplacé comme spécifié par la norme ANSI C standard.Barre oblique inverse des séquences d'échappement, si présents, sont décodés 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

L'élargissement de la raison est une seule cité, comme si le signe dollar n'avait pas été présent.


Voir Citations et d'évasion:En C ANSI, comme les chaînes sur bash-hackers.org wiki pour plus de détails.Notez également que "Bash Changements" fichier (aperçu ici) mentionne un grand nombre de changements et de corrections de bugs liés à l' $'string' citant le mécanisme.

Selon unix.stackexchange.com Comment utiliser un caractère spécial comme un normal? il devrait fonctionner (avec quelques variantes) dans 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:

  

Enfermer caractères guillemets simples   ( « ' ») Conserve la valeur littérale de   chaque caractère entre guillemets. UNE   guillemet simple ne peut pas se produire entre   apostrophes, même si elle est précédée d'un   backslash.

bash ne comprendra pas:

alias x='y \'z '

cependant, vous pouvez le faire si vous entourer de guillemets doubles:

alias x="echo \'y "
> x
> 'y

Je peux confirmer que l'utilisation '\'' pour une seule citation dans une chaîne unique cité fonctionne dans Bash, et il peut être expliqué de la même manière que l'argument « collage » plus tôt dans le fil. Supposons que nous ayons une chaîne entre guillemets: 'A '\''B'\'' C' (toutes les citations ici sont des guillemets simples). Si elle est passée à l'écho, il imprime les éléments suivants: A 'B' C. Dans chaque '\'' la première citation ferme la chaîne unique cité actuelle, les colles \' suivant un guillemet simple à la chaîne précédente (\' est un moyen de spécifier un guillemet simple sans lancer une chaîne entre guillemets), et la dernière citation ouvre un autre simple chaîne entre guillemets.

Exemple simple d'échapper à des citations dans la coquille:

$ echo 'abc'\''abc'
abc'abc
$ echo "abc"\""abc"
abc"abc

Il est fait en terminant déjà ouvert un ('), en plaçant un échappé (\'), puis en ouvrir une autre (de '). Cette syntaxe fonctionne pour toutes les commandes. Il est approche très similaire à la 1ère réponse.

Les deux versions fonctionnent, que ce soit avec concaténation en utilisant le caractère unique de citation échappé (\ « ), ou avec concaténation en enfermant le caractère guillemet simple entre guillemets (" »").

L'auteur de la question n'a pas remarqué qu'il y avait une citation simple supplémentaire ( ') à la fin de sa dernière tentative échapper:

alias rxvt='urxvt -fg'\''#111111'\'' -bg '\''#111111'\''
           │         │┊┊|       │┊┊│     │┊┊│       │┊┊│
           └─STRING──┘┊┊└─STRIN─┘┊┊└─STR─┘┊┊└─STRIN─┘┊┊│
                      ┊┊         ┊┊       ┊┊         ┊┊│
                      ┊┊         ┊┊       ┊┊         ┊┊│
                      └┴─────────┴┴───┰───┴┴─────────┴┘│
                          All escaped single quotes    │
                                                       │
                                                       ?

Comme vous pouvez le voir dans l'art morceau précédent de belle ASCII / Unicode, la dernière citation unique se sont échappés (\ « ) est suivie d'une seule citation nécessaire ( »). En utilisant une syntaxe surligneur comme celui présent dans Notepad ++ peut se révéler très utile.

La même chose est vraie pour un autre exemple comme celui qui suit:

alias rc='sed '"'"':a;N;$!ba;s/\n/, /g'"'"
alias rc='sed '\'':a;N;$!ba;s/\n/, /g'\'

Ces deux cas beaux d'alias montrent d'une manière très complexe et obscurcie comment un fichier peut être aligné vers le bas. C'est, à partir d'un fichier avec beaucoup de lignes que vous obtenez seulement une ligne avec des virgules et des espaces entre le contenu des lignes précédentes. Afin de donner un sens au commentaire précédent, ce qui suit est un exemple:

$ cat Little_Commas.TXT
201737194
201802699
201835214

$ rc Little_Commas.TXT
201737194, 201802699, 201835214

Je ne suis pas spécifiquement d'aborder la question en citant parce que, eh bien, parfois, il est juste raisonnable d'envisager une autre approche.

rxvt() { urxvt -fg "#${1:-000000}" -bg "#${2:-FFFFFF}"; }

que vous pouvez ensuite appeler comme:

rxvt 123456 654321

l'idée étant que vous pouvez maintenant alias cela sans se soucier des citations:

alias rxvt='rxvt 123456 654321'

ou, si vous avez besoin d'inclure le # dans tous les appels pour une raison:

rxvt() { urxvt -fg "${1:-#000000}" -bg "${2:-#FFFFFF}"; }

que vous pouvez ensuite appeler comme:

rxvt '#123456' '#654321'

puis, bien sûr, un alias est:

alias rxvt="rxvt '#123456' '#654321'"

(oups, je suppose que je ne sorte de l'adresse cite:)

Je viens d'utiliser les codes shell .. par exemple \x27 ou \\x22 selon le cas. Pas de problème, jamais vraiment.

Comme on ne peut pas mettre des guillemets simples dans les chaînes entre guillemets simples, l'option la plus simple et la plus lisible est d'utiliser une chaîne de heredoc

command=$(cat <<'COMMAND'
urxvt -fg '#111111' -bg '#111111'
COMMAND
)

alias rxvt=$command

Dans le code ci-dessus, le heredoc est envoyé à la commande cat et la sortie qui est affectée à une variable via la notation substitution de commande $(..)

Mettre un devis autour du heredoc est nécessaire car il est dans un $()

à mon humble avis la vraie réponse est que vous ne pouvez pas échapper à guillemets simples dans les chaînes entre guillemets simples.

Il est impossible.

Si nous présumons que nous utilisons bash.

De manuel 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 "ou \

Il n'y a rien de magique alias qui exige d'utiliser des guillemets simples.

Les deux les travaux suivants en 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 # 111111 qui nécessite des guillemets simples.

Les options suivantes le même résultat 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 également échapper à la problématique # directement

alias rxvt="urxvt -fg \#111111 -bg \#111111"

La plupart de ces réponses a frappé sur le cas précis que vous vous posez au sujet. Il y a une approche générale qu'un ami et moi avons développé qui permet arbitraire de citer au cas où vous devez citer bash commandes à travers de multiples couches d'expansion de la coquille, par exemple, par ssh, su -c, bash -c, etc. Il y a un noyau vous primitif besoin , ici en bash natif:

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
}

Ce fait exactement ce qu'il dit: il shell guillemets individuellement chaque argument (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 fait la chose évidente pour une couche d'expansion:

$ bash -c "$(quote_args echo a'"'b"'"c arg2)"
a"b'c arg2

(Notez que les guillemets doubles autour $(quote_args ...) sont nécessaires pour rendre le résultat en un seul argument pour bash -c.) Et il peut être plus généralement utilisés pour citer correctement à travers de multiples couches d'expansion:

$ bash -c "$(quote_args bash -c "$(quote_args echo a'"'b"'"c arg2)")"
a"b'c arg2

L'exemple ci-dessus:

  1. shell guillemets chaque argument de la quote_args intérieure individuellement et combine ensuite la sortie résultant en un seul argument avec les guillemets doubles internes.
  2. shell guillemets bash, -c, et le résultat déjà une fois cité de l'étape 1, et combine ensuite le résultat dans un seul argument avec les guillemets doubles externes.
  3. envoie ce désordre comme argument à la bash -c externe.

C'est l'idée en quelques mots. Vous pouvez faire des choses assez compliquées avec cela, mais il faut faire attention à l'ordre d'évaluation et dont sont cités sous-chaînes. Par exemple, ce qui suit faire les mauvaises choses (pour une définition de « mauvais »):

$ (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 se dilate immédiatement quote_args cd /; pwd 1>&2 en deux commandes distinctes, quote_args cd / et pwd 1>&2, de sorte que le MDC est encore /tmp lorsque la commande est exécutée pwd. Le deuxième exemple illustre un problème similaire pour les jokers. En effet, le même problème de base se produit avec toutes les extensions de bash. Le problème ici est qu'une substitution de commande n'est pas un appel de fonction. Il est littéralement évaluer un script bash et en utilisant sa sortie dans le cadre d'un autre script bash

Si vous essayez d'échapper à tout simplement les opérateurs de shell, vous allez échouer parce que la chaîne résultante passée à bash -c est juste une séquence de chaînes individuellement cotées qui ne sont pas alors interprétés comme des opérateurs, ce qui est facile de voir si vous l'écho la chaîne qui aurait été passé à 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 ici est que vous avez plus guillemet. Qu'est-ce que vous avez besoin est pour les opérateurs à unquoted en entrée à l'enceinte bash -c, ce qui signifie qu'ils doivent être en dehors de la substitution de commande $(quote_args ...).

Par conséquent, ce que vous avez besoin de la commande ne vise pas à faire dans le sens le plus général est de shell guillemet chaque mot d'être élargi au moment de la substitution de commande séparément, et ne pas appliquer une citation supplémentaire aux opérateurs 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 cela, la chaîne entière est un jeu juste pour citer encore à 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 surmené étant donné que des mots comme success, sbin et pwd ne doivent pas nécessairement être shell cité, mais le point essentiel à retenir lors de l'écriture d'un script prenant entrée arbitraire est que vous voulez citer tout ce que vous n'êtes pas absolument sûr ne 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érer 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é, il suffit d'utiliser des guillemets doubles au lieu de guillemets simples comme mécanisme d'échappement externe:

alias rxvt="urxvt -fg '#111111' -bg '#111111'"

Cette approche est adaptée à de nombreux cas où vous voulez juste passer une chaîne fixée à une commande:. Vérifiez simplement comment le shell interprète la chaîne double cité par un echo et des caractères d'échappement avec barre oblique inverse si nécessaire

Dans l'exemple, vous verriez que des guillemets doubles sont suffisantes pour protéger la chaîne:

$ echo "urxvt -fg '#111111' -bg '#111111'"
urxvt -fg '#111111' -bg '#111111'

Voici une élaboration d'une véritable réponse mentionné ci-dessus:

Parfois, je téléchargerai en utilisant rsync sur ssh et doivent échapper à un nom de fichier avec un "dans DEUX FOIS! (OMG!) Une fois pour bash et une fois pour ssh. Le même principe d'alternance délimiteurs de citation est à l'œuvre ici.

Par exemple, disons que nous voulons: Histoires LA Louis Theroux ...

  1. D'abord, vous entourez Louis Theroux entre guillemets simples pour bash et des guillemets doubles pour ssh: 'Louis Theroux "'
  2. Ensuite, vous utilisez des guillemets simples pour échapper à une double citation « " »
  3. L'utilisation des guillemets doubles pour échapper à l'apostrophe "'"
  4. Ensuite, répétez 2, en utilisant des guillemets simples pour échapper à un guillemet « " »
  5. , puis entourez LA Histoires dans des guillemets simples pour bash et des guillemets doubles pour ssh: "LA Stories"

Et voici! Vous liquidez 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 cotation imbriquées:

Vous essayez de caser trop dans un trop petit espace, utilisez donc une fonction bash.

Le problème est que vous essayez d'avoir trop de niveaux d'imbrication et la technologie de l'alias de base n'est pas assez puissant pour accueillir. Utilisez une fonction bash comme celui-ci pour le faire de sorte que les chambres simples, doubles guillemets arrière tiques et passé dans les paramètres sont tous traités normalement nous attendre:

lets_do_some_stuff() {
    tmp=$1                       #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

Ensuite, vous pouvez utiliser votre 1 $ et 2 $ variables et simples, des guillemets doubles et les tiques arrière sans se soucier de la fonction d'alias leur intégrité wrecking.

Ce programme affiche:

el@defiant ~/code $ foobarbaz alien Dyson ring detected @grid 10385
alien Dyson ring detected @grid 10385
-------------
Mon Oct 26 20:30:14 EDT 2015
-------------
shell_escape () {
    printf '%s' "'${1//\'/\'\\\'\'}'"
}

explication de mise en œuvre:

  • guillemets doubles pour que nous puissions facilement emballage sortie des guillemets simples et utilisez la syntaxe ${...}

  • la recherche de bash et remplacer ressemble: ${varname//search/replacement}

  • nous remplaçons ' avec '\''

  • '\'' code pour un seul ' comme ceci:

    1. ' met fin à la seule citer

    2. \' code pour une ' (la barre oblique inverse est nécessaire parce que nous ne sommes pas à l'intérieur de guillemets)

    3. ' démarre seul pour citer à nouveau

    4. bash concaténer automatiquement les chaînes sans espace entre

  • il y a un \ avant chaque \ et ' parce que c'est les règles qui s'échappent pour ${...//.../...}.

string="That's "'#@$*&^`(@#'
echo "original: $string"
echo "encoded:  $(shell_escape "$string")"
echo "expanded: $(bash -c "echo $(shell_escape "$string")")"

P.S. Toujours encoder à singulariser les chaînes entre guillemets, car ils sont beaucoup plus simples que doubles guillemets.

Si vous avez parallèle GNU installé, vous pouvez utiliser la citation interne:

$ parallel --shellquote
L's 12" record
<Ctrl-D>
'L'"'"'s 12" record'
$ echo 'L'"'"'s 12" record'
L's 12" record

Depuis la version 20190222 vous pouvez même --shellquote plusieurs fois:

$ parallel --shellquote --shellquote --shellquote
L's 12" record
<Ctrl-D>
'"'"'"'"'"'"'L'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'s 12" record'"'"'"'"'"'"'
$ eval eval echo '"'"'"'"'"'"'L'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'s 12" record'"'"'"'"'"'"'
L's 12" record

Il cite la chaîne dans toutes les coquilles pris en charge (non seulement bash).

Cette fonction:

quote () 
{ 
    local quoted=${1//\'/\'\\\'\'};
    printf "'%s'" "$quoted"
}

permet de citer ' à l'intérieur '. Utilisez comme ceci:

$ quote "urxvt -fg '#111111' -bg '#111111'"
'urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''

Si la ligne de citation est plus complexe, comme des guillemets doubles mixtes avec des guillemets simples, il peut devenir assez 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 l'intérieur d'un script (similaire à ce sujet).

#!/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_

Affichera:

'urxvt -fg '\''#111111'\'' -bg '\''#111111'\'''
'Louis Theroux'\''s LA Stories'
''\''single quote phrase'\'' "double quote phrase"'

Toutes les chaînes entre guillemets correctement à l'intérieur des guillemets simples.

De toute évidence, il serait plus facile simplement entourer de guillemets doubles, mais où est le défi dans tout cela? Voici la réponse en utilisant uniquement des guillemets simples. J'utilise une variable au lieu de alias si c'est qu'il est plus facile d'imprimer pour preuve, mais il est le même que l'utilisation alias.

$ rxvt='urxvt -fg '\''#111111'\'' -bg '\''#111111'\'
$ echo $rxvt
urxvt -fg '#111111' -bg '#111111'

Explication

La clé est que vous pouvez fermer la seule offre et rouvrir autant de fois que vous le souhaitez. Par exemple foo='a''b' est le même que foo='ab'. Ainsi, vous pouvez fermer la seule citation, jeter dans un \' guillemet simple littéral, puis rouvrez la citation suivante unique.

diagramme de répartition

Ce diagramme montre clairement à l'aide des crochets pour montrer où les guillemets simples sont ouvertes et fermées. Guillemets ne sont pas « imbriquées » comme entre parenthèses peuvent être. Vous pouvez aussi faire attention à la mise en valeur des couleurs, ce qui est correctement appliquée. Les chaînes entre guillemets sont rouge foncé, tandis que le \' est noir.

'urxvt -fg '\''#111111'\'' -bg '\''#111111'\'    # original
[^^^^^^^^^^] ^[^^^^^^^] ^[^^^^^] ^[^^^^^^^] ^    # show open/close quotes
 urxvt -fg   ' #111111  '  -bg   ' #111111  '    # literal characters remaining

(Ceci est essentiellement la même réponse que Adrian de, mais je me sens ce qui explique mieux. Aussi sa réponse a 2 apostrophes superflu à la fin.)

Voici une autre solution. Cette fonction prend un seul argument et citer de façon appropriée en utilisant le caractère guillemet simple, tout comme la réponse voté 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'"
}

Alors, 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 au sein de 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()]))

Affichera:

foo ain't "bad" so there!
foo 'ain'"'"'t' '"bad"' so 'there!'
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top