Journal Échapement des caractères spéciaux sous unix

Posté par  (site web personnel) .
Étiquettes : aucune
0
23
juil.
2009
Suite au journal de mildred[1] sur son alternative à make, un petit début sur les caractères spéciaux et les méthodes d'échappement à commencé.

Pour ceux qui l'ignorent, en shell (et j'imagine que make fait dans le même genre) vous avez trois méthode d'échappement
* Le backslash qui échappe le caractère suivant : un\ nom\ complexe
* Les guillemets simples, 'un nom complexe'
* Les guillemets double, qui permettent l'interpolation de variable : "un $nom complexe"

Les choses se compliquent lorsque vous voulez faire du traitement par lot sur des fichiers qui peuvent potentiellement contenir des guillemets double ou simple. En effet, dans des scripts (propres), on utilisera des guillemets pour se prévenir des problèmes liés à d'autres caractères spéciaux (l'espace par exemple). Des guillemets simple peuvent contenir des guillemets double et inversement, mais si on à les deux dans un lot ou dans un seul fichier, cela ne fonctionne plus.

À priori un simple filtre qui échappe tous les caractères spéciaux avec un backslash devrait faire l'affaire.

N'ayant pas trouvé de filtre adéquate[2], je me suis donc un peu penché sur la question, et j'ai pondu le code (quick and dirty) suivant :

#!/usr/bin/perl
#?
sub escaped {
s/\\/\\\\/g; # backslash
s/\ /\\\ /g; # espace
s/\'/\\\'/g; # guillemet, etc.
s/\"/\\\"/g;
s/\(/\\\(/g;
s/\)/\\\)/g;
# Vous pouvez en ajouter d'autres bien sûr
return $_;
}
#? pour chaque ligne lue
while(<>){
#? Afficher le résultat de l'échappement sur la ligne courante
print escaped( $_);
}


Et son application :

% ls *.ex
file"with"quotes( and 'simple').ex
% ls *.ex|./escape.pl
file\"with\"quotes\(\ and\ \'simple\'\).ex


Seulement voila, si je fait un copier/coller du résultat, c'est bon, mais pas si je l'utilise directement:

#copié de ci-dessus
% cat file\"with\"quotes\(\ and\ \'simple\'\).ex
tada !
% cat $(ls *.ex|./escape.pl)
cat: file\"with\"quotes\(\: Aucun fichier ou dossier de ce type
cat: and\: Aucun fichier ou dossier de ce type
cat: \'simple\'\).ex: Aucun fichier ou dossier de ce type


Bon, visiblement il ne prends pas mon échappement d'espace et considère les espaces comme des séparateur d'arguments. Résultat assez inattendu puisqu'à priori il mange exactement la même chaîne de caractère qu'au dessus.

Voilà, à vos commentaires !

[1] http://linuxfr.org/~mildred/28576.html
[2] Il y avait bien http://search.cpan.org/dist/String-Escape/Escape.pm mais il n'échappe pas les guillemets simples.
  • # C'est pas utilie pour GNU ls

    Posté par  . Évalué à 3.

    Comme je l'ai écris dans le journal de mildred, le ls de GNU a une option pour échapper les caractères. Ce n'est donc pas l'application pour laquelle ton code est le plus utile.

    Exemple:

    $ touch t\'est
    $ ls --quoting-style=shell
    't'\''est'

    « Rappelez-vous toujours que si la Gestapo avait les moyens de vous faire parler, les politiciens ont, eux, les moyens de vous faire taire. » Coluche

    • [^] # Re: C'est pas utilie pour GNU ls

      Posté par  (site web personnel) . Évalué à 2.

      Oui mais le but ici c'est d'avoir un solution générique, que tu peux utiliser en combinaison avec xargs par exemple. Comme ça tu devrais pouvoir utiliser ça même dans les makefiles du genre :

      escape $@ $+ | xargs $(GENPDF) -o

      pour reprendre l'exemple du journal de mildred.
  • # Où est le problème ?

    Posté par  . Évalué à 2.

    $ ls
    a ()'"
    $ cat "$(ls *)"
    Hello, world
    • [^] # Re: Où est le problème ?

      Posté par  (site web personnel) . Évalué à 2.

      Y en a pas pour un ls, mais dans un makefile avec des règles générales sur les cibles, ($@…) c'est plus problématique.
      • [^] # Re: Où est le problème ?

        Posté par  . Évalué à 2.

        Le problème provient de la substitution des variables de make vers le script shell, tu pourras pas le résoudre avec un script shell: au moment où il sera appelé, il sera trop tard.
  • # IFS

    Posté par  . Évalué à 4.

    Tu as un problème de Internal Field Separtor.
    Le ls va envoyer dans le pipe une ligne avec un espace qui sera interprété comme un séparateur.

    (un truc du genre
    OLDIFS=$IFS
    IFS=$'\n'
    ton cat
    *puis*
    IFS=$OLDIFS
    devrait t'aider)
  • # Une réponse

    Posté par  (site web personnel) . Évalué à 1.

    ...mais ça s'applique peut-être pas dans ton cas


    eval cat "`ls *.ex|./escape.pl`"
  • # simple quotes

    Posté par  (site web personnel) . Évalué à 1.

    J'ai entandu parler que les simples quotes ne pouvaient pas s'échapper. C'est d'ailleurs ainsi que certaines personnes ont pu prendre le contrôle de fonera:


    As you can see, FON did take some precautions to prevent people injecting code: Parameters are enclosed in single quotes to avoid substitutions of any kind. The entering of strange characters is prohibited by the web interface, and even if you manage to get a single quote character into your ESSID, it will be "defused" by prepending a backslash to it.

    [...]

    But wait, is it? I was quite surprised when I consulted the bash manual page:

    "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."


    Pour traduire la page de manuel:

    Chaque caractère dans des simples quotes préserve son sens. Une simple quote ne peux pas être présente au milieu d'une chaîne de caractères délimitée par de simples quotes, même si elle est précédée par un antislash.

    http://stefans.datenbruch.de/lafonera/
    • [^] # Re: simple quotes

      Posté par  (site web personnel) . Évalué à 2.

      Et en échappant tous les caractères spéciaux avec une un backslash, sans mettre le tout entre guillemets ?
      • [^] # Re: simple quotes

        Posté par  (site web personnel) . Évalué à 1.

        tout à fait. Bien sûr que les simples quotes peuvent être échappées !

        Dans le langage de prog. que j'utilise quotidiennement, la fonction de bibliothèque qui fait cet échappement destiné au shell fonctionne comme ceci:

        - la chaîne est mise entre simple quote
        - les simple quotes à l'intérieur sont remplacées par '\''

        par exemple:

        abc"def'ghi

        => 'abc"def'\''ghi'

        ça donne un truc simple et lisible quand y'a pas de ' dans la chaîne (et un moins lisible quand y'en a, certes)
        • [^] # Re: simple quotes

          Posté par  (site web personnel) . Évalué à 1.

          Moi, re faisait un remplacement

          ' -> ' " ' " ' (sans les espaces)

          ça donne:

          abc"def'ghi -> 'abc"def'"'"'ghi'

          mais ce que je voulais dire c'est que ce n'est pas comme on pourrait penser \'
  • # use String::ShellQuote;

    Posté par  (site web personnel) . Évalué à 1.

    J'ai pas compris la problématique ou c'est juste pour faire ce que fait ça : http://search.cpan.org/dist/String-ShellQuote/shell-quote

    ??


    use String::ShellQuote;
    my $workdir = shell_quote($opt_workdir);

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.