Comment échapper à des citations en shell?


66

J'ai des problèmes avec les personnages qui échappent à Bash. J'aimerais échapper aux guillemets simples et doubles lors de l'exécution d'une commande sous un autre utilisateur. Aux fins de cette question, disons que je veux faire écho à ce qui suit à l'écran:

'single quote phrase' "double quote phrase"

Comment puis-je échapper à tous les caractères spéciaux, si je dois également basculer vers un autre utilisateur:

sudo su USER -c "echo \"'single quote phrase' \"double quote phrase\"\""

Bien sûr, cela ne produit pas le bon résultat.


+1 pour "Bien sûr, cela ne donne pas les bons résultats". bashest bien sur le chemin de me rendre fou.
Rolf

Réponses:


89

Vous pouvez utiliser la syntaxe littérale de chaîne suivante:

> echo $'\'single quote phrase\' "double quote phrase"'
'single quote phrase' "double quote phrase"

De man bash

Les mots de la forme $ 'chaîne' sont traités spécialement. Le mot se développe en chaîne, avec les caractères d'échappement avec une barre oblique inversée remplacés comme spécifié par la norme ANSI C. Les séquences d'échappement de barre oblique inverse, le cas échéant, 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
          \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)
          \cx    a control-x character

5
Overkill. Dans la plupart des cas, vous n'avez pas besoin d'utiliser la syntaxe littérale de chaîne.
fpmurphy


12

Dans un shell POSIX, en supposant que dans votre chaîne, il n'y a pas de développement de variable, de commande ou d'historique, et il n'y a pas de saut de ligne, suivez ces recommandations de base:

  1. Pour citer une chaîne générique avec des guillemets simples, procédez comme suit:

    1. Remplacez toute séquence de caractères sans guillemets ayant la même séquence, avec des guillemets simples ajoutés et finis: 'aaa' ==> ''aaa''

    2. Echappez avec une barre oblique inverse chaque caractère guillemet simple préexistant : ' ==> \'
      en particulier,''aaa'' ==> \''aaa'\'

  2. Pour citer une chaîne générique avec des guillemets, procédez comme suit:

    1. Ajoutez des guillemets doubles de début et de fin: aaa ==> "aaa"

    2. Echappez-vous avec une barre oblique inverse pour chaque caractère guillemet double et pour chaque caractère barre oblique inversée: " ==> \", \ ==> \\

Quelques exemples:

''aaa""bbb''ccc\\ddd''  ==>  \'\''aaa""bbb'\'\''ccc\\ddd'\'\'
                        ==>  "''aaa\"\"bbb''ccc\\\\ddd''"

afin que votre exemple puisse être développé avec ce qui suit:

#!/bin/sh

echo \''aaa'\'' "bbb"'
echo "'aaa' \"bbb\""

sudo su enzotib -c 'echo \'\'\''aaa'\''\'\'\'' "bbb"'\'
sudo su enzotib -c 'echo "'\''aaa'\'' \"bbb\""'

sudo su enzotib -c "echo \\''aaa'\\'' \"bbb\"'"
sudo su enzotib -c "echo \"'aaa' \\\"bbb\\\"\""

10

Exemple simple d'écriture de citations dans un shell:

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

Cela se fait en finissant un déjà ouvert ( '), en plaçant un échappé ( \'), puis en en ouvrant un autre ( ').

Alternativement:

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

Cela se fait en finissant un déjà ouvert ( '), en plaçant quote dans un autre quote ( "'"), puis en en ouvrant un autre ( ').

Connexe: Comment échapper à des guillemets simples dans des chaînes à une seule citation? à stackoverflow SE


1

La réponse acceptée fonctionne pour une citation simple (un niveau):

$ echo $'\'single quote phrase\' "double quote phrase"'
'single quote phrase' "double quote phrase"

Pour que la commande présentée fonctionne, vous devez citer deux fois.
Ce script pourrait faire tout le travail:

#!/bin/bash

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

read -r line <<-\_line_to_quote_
'single quote phrase' "double quote phrase"
_line_to_quote_

quote "$line"; echo
quote "echo $(quote "$line")"; echo

Exécutez le script pour obtenir:

$ script
''\''single quote phrase'\'' "double quote phrase"'
'echo '\'''\''\'\'''\''single quote phrase'\''\'\'''\'' "double quote phrase"'\'''

La première ligne fonctionne pour un écho simple:

$ echo ''\''single quote phrase'\'' "double quote phrase"'
'single quote phrase' "double quote phrase"

La deuxième ligne fonctionnera pour la commande à double guillemet:

sudo su USER -c 'echo '\'''\''\'\'''\''single quote phrase'\''\'\'''\'' "double quote phrase"'\'''

-3

echo 'Je suis un étudiant' ne fonctionne pas. Mais les travaux suivants:

echo $ 'Je suis un étudiant' De la page de manuel de bash:

Un seul guillemet ne peut pas apparaître entre guillemets, même s'il est précédé d'une barre oblique inverse. .... Les mots de la forme $ 'chaîne' sont traités spécialement. Le mot se développe en chaîne, avec les caractères d'échappement avec une barre oblique inversée remplacés comme spécifié par la norme ANSI C.


6
Cela n'ajoute rien aux réponses existantes.
jasonwryan
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.