web-dev-qa-db-fra.com

Échapper une variable pour l'utiliser comme contenu d'un autre script

Cette question est pas sur la façon d'écrire un littéral de chaîne correctement échappé. Je n'ai trouvé aucune question connexe qui ne concerne pas comment échapper des variables pour une consommation directe dans un script ou par d'autres programmes.

Mon objectif est de permettre à un script de générer d'autres scripts. En effet, les tâches dans les scripts générés s'exécuteront de 0 à n fois sur une autre machine, et les données à partir desquelles elles sont générées peuvent changer avant d'être exécutées (à nouveau), opérations directement, sur un réseau ne fonctionnera pas.

Étant donné une variable connue qui peut contenir des caractères spéciaux tels que des guillemets simples, je dois l'écrire comme un littéral de chaîne entièrement échappé, par exemple une variable foo contenant bar'baz devrait apparaître dans le script généré sous la forme:

qux='bar'\''baz'

qui serait écrit en ajoutant "qux=$foo_esc" aux autres lignes de script. Je l'ai fait en utilisant Perl comme ceci:

foo_esc="'`Perl -pe 's/('\'')/\\1\\\\\\1\\1/g' <<<"$foo"`'"

mais cela semble exagéré.

Je n'ai pas réussi à le faire avec bash seul. J'en ai essayé de nombreuses variantes:

foo_esc="'${file//\'/\'\\\'\'}'"
foo_esc="'${file//\'/'\\''}'"

mais soit des barres obliques supplémentaires apparaissent dans la sortie (quand je fais echo "$foo"), ou ils provoquent une erreur de syntaxe (en attendant d'autres entrées si cela est fait à partir du shell).

22
Walf

Je suppose que je n'ai pas RTFM. Cela peut se faire comme suit:

q_mid=\'\\\'\'
foo_esc="'${foo//\'/$q_mid}'"

Alors echo "$foo_esc" Donne le 'bar'\''baz' Attendu


Comment je l'utilise avec une fonction:

function esc_var {
    local mid_q=\'\\\'\'
    printf '%s' "'${1//\'/$mid_q}'"
}

...

foo_esc="`esc_var "$foo"`"

Modifier ceci pour utiliser le printf intégré de la solution de Dejay:

function esc_vars {
    printf '%q' "$@"
}
8
Walf

Bash a une option d'extension de paramètre pour exactement ce cas :

${parameter@Q} L'expansion est une chaîne qui est la valeur du paramètre cité dans un format qui peut être réutilisé en entrée.

Donc dans ce cas:

foo_esc="${foo@Q}"

Ceci est pris en charge dans Bash 4.4 et versions ultérieures. Il existe également plusieurs options pour d'autres formes d'extension et pour générer spécifiquement des instructions d'affectation complètes (@A).

33
Michael Homer

Bash fournit un printf intégré avec %q spécificateur de format, qui effectue l'échappement Shell pour vous, même dans les anciennes versions (<4.0) de Bash:

printf '[%q]\n' "Ne'er do well"
# Prints [Ne\'er\ do\ well]

printf '[%q]\n' 'Sneaky injection $( whoami ) `ls /root`'
# Prints [Sneaky\ injection\ \$\(\ whoami\ \)\ \`ls\ /root\`]

Cette astuce peut également être utilisée pour renvoyer des tableaux de données à partir d'une fonction:

function getData()
{
  printf '%q ' "He'll say hi" 'or `whoami`' 'and then $( byebye )'
}

declare -a DATA="( $( getData ) )"
printf 'DATA: [%q]\n' "${DATA[@]}"
# Prints:
# DATA: [He\'ll\ say\ hi]
# DATA: [or\ \`whoami\`]
# DATA: [and\ then\ \$\(\ byebye\ \)]

Notez que l'utilitaire Bash printf est différent de l'utilitaire printf fourni avec la plupart des systèmes d'exploitation de type Unix. Si, pour une raison quelconque, la commande printf appelle l'utilitaire au lieu du module intégré, vous pouvez toujours exécuter builtin printf au lieu.

14
Dejay Clayton

Il existe plusieurs solutions pour citer une valeur var:

  1. alias
    Dans la plupart des shells (où l'alias est disponible) (sauf csh, tcsh et probablement d'autres comme csh):

    $ alias qux=bar\'baz
    $ alias qux
    qux='bar'\''baz'
    

    Oui, cela fonctionne dans de nombreux shells de type sh comme les tirets ou les cendres.

  2. ensemble
    Également dans la plupart des shells (encore une fois, pas csh):

    $ qux=bar\'baz
    $ set | grep '^qux='
    qux='bar'\''baz'
    
  3. composer
    Dans certains shells (ksh, bash et zsh au moins):

    $ qux=bar\'baz
    $ typeset -p qux
    typeset qux='bar'\''baz'             # this is zsh, quoting style may
                                         # be different for other shells.
    
  4. exportation
    Faites d'abord:

    export qux=bar\'baz
    

    Utilisez ensuite:
    kshexport -p | grep 'qux='bashexport -p | grep 'qux='
    zshexport -p qux

  5. citation
    bashecho "${qux@Q}"
    zshecho "${(qq)qux}" # de un à quatre q peut être utilisé.

5
Isaac