[shell posix] afficher une chaine avec ses backslashs

Bonjour,

J’essaye de faire une fonction qui puisse afficher une chaine de caractères sans effacer les backslashs, et en faisant une action sur chaque ligne (délimitées par des retours chariots).

Pour l’instant j’ai fait ça :

afficher() { chaines="$1" while read une_chaine; do echo voila une chaine "$une_chaine" done <<delimiter $chaines delimiter }

Mais le problème est que si l’argument passé à la fonction contient un backslash, il est supprimé :

$ chaine='\a \b' $ echo "$chaine" \a \b $ afficher "$chaines" voila une chaine a voila une chaine b

Connaissez-vous une astuce pour empêcher le shell de mettre le bazard dans les chaînes de caractères ?

bonjour à tous,
si tu as la main sur le format de sortie des messages tu peux doubler le caractère d’échappement :

:-) $ afficher '\\A' voila une chaine \A :-) $
Car le caractère d’échappement du caractère d’échappement est… le caractère d’échappement ! :wink:
Dans le cas contraire, on peut imaginer un doublement par une commande “sed” via des tubes du genre :

l'appli_qui_sort_le_\ | une_commande_sed_qui_double_les_\ | afficher

Après, je ne connais pas d’option à echo ou printf permettant de faire ce que tu veux. Cela ne veux pas dire qu’elle n’existe pas…
Dans tous les cas on peut tester dans le script “afficher” caractère par caractère, mais pour des fichiers volumineux, cela risque de consommer beaucoup de ressource système… Une petit programme en C serait le bien venu… :wink:

Merci ! Ce n’est pas bête du tout ça de doubler les basckslashs.

Mais j’aimerai une solution plus universelle (qui marche aussi pour les étoiles) :

afficher() { chaine='$'"$1" for ligne in $( eval "echo \"\"$chaine\"\"" ); do echo une ligne "$ligne" done }

Ca marche presque : mais il y a encore les étoiles qui sont remplacées par le contenu du répertoire :

[code]$ chaine=’\a
\b
*


*
$abcd
$abcd’[/code]

Mais quel est ton but exactement ?
Car si tu souhaites faire des traitements ligne par ligne (même un tout bête affichage), les commandes sed ou awk sont vraiment faites pour cela.
Le shell (bash ?) n’est pas trés maniable pour les cas complexes… :frowning:

Oui … c’est vraiment pas pratique. En fait, plus j’apprends le shell et plus je déteste ce langage. Impossible d’affecter le contenu d’une variable à une autre sans que ce contenu soit “interprété” à tout va. Vraiment insupportable, on ne peut pas faire un code qui tienne la route.

Il faut que je me trouve un langage de scripts qui, bien qu’interprété, fournissent des variables dignes de ce nom. Et qui ne modifie des trucs que lorsqu’on le demande.

Je ne m’étais jamais posé la question avant, mais là je me demande vraiment pourquoi cette horreur sert de langage de script de base sur tout les systèmes Unix du monde. A moins d’être un expert, c’est un nid à bugs.

Bon après avoir vidé mon sac, je réponds à ta question : mon but est d’arriver à manipuler des variables comme on le ferait dans n’importe quel langage de programmation normal. C’est à dire en maîtrisant le contenu d’une chaîne de caractères à l’octet près. Mais j’abandonne, car même si j’arrivais à faire cette prouesse, si jamais je fais un “echo” du contenu de la variable, tout est modifié.

En tout cas merci d’avoir essayer de résoudre mon problème insoluble.


Au fait pour sed et awk, il y a toujours le même problème, au moment de passer les données à traiter à ces langages, il y aura une expansion faite par le shell. En fait, il faut toujours laisser les données dans des fichiers et les manipuler avec des commandes pour assurer leur intégrité. Donc pour résumer, les variables du shell sont stockées sur le disque dur (c’est pas terrible au niveau des perfs).


Yeah !! :115 :115 :115 J’ai trouvé la solution pour faire des trucs potables : stocker le contenu des variables dans des fichiers se trouvant dans le répertoire [size=110]/dev/shm[/size] !

Comme ça on a les perfs et la sûreté. :041

[quote]Je ne m’étais jamais posé la question avant, mais là je me demande vraiment pourquoi cette horreur sert de langage de script de base sur tout les systèmes Unix du monde. A moins d’être un expert, c’est un nid à bugs.
[/quote]
En fait le shell, n’est pas prévu pour traiter des bases de données, même sous forme de fichier plat. Son rôle se borne à une interface utilisateur / noyau (en gros).

Vois-tu, on ne peut pas en vouloir au shell d’interpréter des commandes et des variables, c’est tout de même sont but premier ! :wink:
Si tu veux interpréter de façon efficace un fichier plat avec des champs un peu biscornus, c’est awk qu’il te faut. Une commande awk s’intègre parfaitement dans un script shell. Il y a des tas de tutos sur le net.
Une dernière chose : il existe une commande basic d’extraction de chaîne dans le shell. C’est ${}

:-) $ var="AZERTYUIOP" :-) $ printf "${var#AZE}\n" RTYUIOP :-) $ var="AZERT\YUIOP" :-) $ printf "${var#AZE}\n" RT\YUIOP :-) $
Il y a d’autres caractères de contrôle que tu trouvera sans doute facilement sur internet. Les tutos ne manquent pas. :041

Pour awk, je crois que j’ai des liens dans ma besace… Si ça t’intéresse…
http://www.bruno-garcia.net/www/Unix/Docs/awk.html
http://sunsite.ualberta.ca/Documentation/Gnu/gawk-3.0.6/html_chapter/gawk_toc.html#SEC_Contents

Merci pour les liens, oui awk m’intéresse. J’avais déjà lu le man mais un cours plus complet est indispensable.
L’extraction de chaîne est bien utile aussi, ça me permettra souvent de me passer de grep.

J’ai poussé les recherches sur le site de l’opengroup et j’ai réussi à trouver des techniques pour désactiver certaines expansions :

  1. Désactiver la décomposition du résultat des commandes en éléments afin de préserver les espaces. Il faut mettre la variable IFS égal à la chaine vide ‘’. Voir posix shell field splitting.

  2. Utiliser l’option -r de la commande read permet de considérer les backslashs comme des caractères normaux. Voir posix shell read utility.

  3. Les backslashs \ , quotes ’ et guillemets " sont toujours supprimés lors de l’évaluation d’une instruction, sauf s’ils sont échappés avec un backslash \ , ou avec des quotes ’ , ou avec des guillemets ". Voir posix shell quote removal.
    Voici la commande sed qui permet de rajouter un backslash devant toutes les occurences de ces trois caractères :

  1. La commande echo ne permet pas de gérer les backslashs de manière portable. Il faut utiliser printf à la place. Elle permet un contrôle beaucoup plus fin de ce qui est affiché. Voir posix shell echo utility et posix shell printf utility

En fait je viens de me rendre compte que tu m’as donné la solution pour mon problème initial. Pour afficher une chaine avec ses backslashs :

printf '%s\n' "$ma_chaine" :obscene-hanged: