web-dev-qa-db-fra.com

Comment échapper aux citations en shell?

J'ai du mal à échapper les personnages dans bash. Je voudrais é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 passer à 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.

82
m33lky

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 $ 'string' sont traités spécialement. Le mot se développe en chaîne, avec des caractères d'échappement antislash remplacés comme spécifié par la norme C ANSI. Les séquences d'échappement de barre oblique inverse, 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
          \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
110
SiegeX

Exemple simple d'échapper des guillemets dans Shell:

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

Cela se fait en terminant un déjà ouvert ('), En plaçant un d'échappement (\'), Puis en ouvrant un autre (').

Alternativement:

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

Cela se fait en terminant un déjà ouvert ('), En plaçant un devis dans un autre devis ("'"), Puis en ouvrant un autre (').

Connexes: Comment échapper les guillemets simples dans les chaînes entre guillemets simples? at stackoverflow SE

17
kenorb

Dans un shell POSIX, en supposant dans votre chaîne qu'il n'y a pas de variable, de commande ou d'extension d'historique, et qu'il n'y ait pas de nouvelle ligne, suivez ces prescriptions de base:

  1. Pour citer une chaîne générique avec des guillemets simples, effectuez les actions suivantes:

    1. Remplacez toute séquence de caractères non-guillemets simples par la même séquence par des guillemets simples de début et de fin ajoutés: 'aaa' ==> ''aaa''

    2. Échapper avec une barre oblique inversée tous les préexistant guillemet simple: ' ==> \'
      En particulier, ''aaa'' ==> \''aaa'\'

  2. Pour citer une chaîne générique avec des guillemets doubles, effectuez les actions suivantes:

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

    2. Échappez-vous avec une barre oblique inverse chaque caractère de guillemet double et chaque caractère barre oblique inverse: " ==> \", \ ==> \\

Quelques exemples:

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

afin que votre exemple puisse être développé avec les éléments suivants:

#!/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\\\"\""
12
enzotib

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

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

Pour faire fonctionner la commande, 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 entre guillemets:

Sudo su USER -c 'echo '\'''\''\'\'''\''single quote phrase'\''\'\'''\'' "double quote phrase"'\'''
2
user79743