Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 24/01/2010, à 16:42

chris_wafer

[Script shell] Script d'alignement / De l'aide?

Bonjour,

Voilà ce que je veux essayer de faire en BASH et/ou AWK :

FICHIER EN ENTRE

 l.1 Ma premier ligne    PATTERN_1 Mon premier pattern de la ligne 1    PATTERN_2 Mon deuxième pattern de la ligne 1
 l.2 Ma deuxième ligne    PATTERN_1 Mon deuxième pattern de la ligne 1    PATTERN_2 Mon deuxième pattern de la ligne 1
 l.3 Ma ligne sans pattern
 l.4 Ma troisième lignes plus longue   PATTERN_1     Mon troisième pattern de la ligne 1    PATTERN_2 Mon troisième pattern de la ligne 1
 l.5 Ma quatrième ligne ligne    PATTERN_1 Mon quatrième pattern de la ligne 1    PATTERN_2 Mon quatrième pattern de la ligne 1

BUT DU SCRIPT
Le but est que mon script prenne en paramètres :
  - le numéro de colonne pour le PATTERN1 : COL_PATTERN1
  - le numéro de colonne pour le PATTERN2 : COL_PATTERN2

ALGORITHME DU SCRIPT
Et son algorithme est si :
  - si la ligne contient le PATTERN1 :
          - si le pattern 1 commence à une colonne < COL_PATTERN1 alors ajouter des espaces pour arriver à être à la COL_PATTERN1
          - si le pattern 1 commence à une colonne > COL_PATTERN1 alors aller à la ligne, mettre le caractère > en début de la ligne et  ajouter des espaces pour arriver à être à la COL_PATTERN1
  - même séquence que précédemment pour le PATTERN2

RÉSULTAT
Au final on arrive au résultat suivant :

  > aligner_pattern 26 72
l.1 Ma premier ligne         PATTERN_1 Mon premier pattern de la ligne 1   PATTERN_2 Mon deuxième pattern de la ligne 1
l.2 Ma deuxième ligne        PATTERN_1 Mon deuxième pattern de la ligne 1  PATTERN_2 Mon deuxième pattern de la ligne 1
l.3 Ma ligne sans pattern
l.4 Ma troisième lignes plus longue
l.5 >                        PATTERN_1     Mon troisième pattern de la ligne 1
l.6 >                                                                      PATTERN_2 Mon troisième pattern de la ligne 1
l.7 Ma quatrième ligne ligne PATTERN_1 Mon quatrième pattern de la ligne 1 PATTERN_2 Mon quatrième pattern de la ligne 1

Merci d'avance pour votre aide, idées... et vos sources... car je ne sais vraiment pas comment faire...


Chris.

Hors ligne

#2 Le 24/01/2010, à 19:55

Zaxou

Re : [Script shell] Script d'alignement / De l'aide?

#! /usr/bin/awk -f
#
# place l'un en face de l'autre 2 mots ou nombre situés dans un meme champ
# le délimiteur étant l'espace
#
# fich 1         fich 2       fich_sortie
# 1 2 3          10 20 30     1 10
# 4 5 6          40 50 60 --> 2 20
# 7 8 9          70 80 90     3 30
#                              ...
#                             8 80
#                             9 90

{
  a= NF*(NR-1) 
  if( FNR==1 && a != 0){
	nblign=a
	}
  for ( i=1; i <= NF ; i++) {
	tab[a+i-1]= $i
	} 
}
END{
	for (a=0; a < nblign; a++) {
		print tab[a], tab[a+nblign]
	}
}

Voici ma première réalisation de script awk; il est largement améliorable car avec ce code il faut que le nombre de champ soit toujours identique (modifiable avec un a+=NF). De plus il ne gère pas le curseur comme tu le voulais (je ne sais pas comment on fait puisque je débute), mais ca peut peut-être déjà te donner une idée... enfin je l'espere.;)

Hors ligne

#3 Le 24/01/2010, à 21:19

boutor

Re : [Script shell] Script d'alignement / De l'aide?

Attention, Zaxou, ton code ne marche pas si :

# fich 1         fich 2      
# 1 2 3          10 20 30 
# 4 5 6          40 50 60 
# 7 8             70 80
#! /usr/bin/awk -f
#
# place l'un en face de l'autre 2 mots ou nombre situés dans un meme champ
# le délimiteur étant l'espace
#
# fich 1         fich 2       fich_sortie
# 1 2 3          10 20 30     1 10
# 4 5 6          40 50 60 --> 2 20
# 7 8 9          70 80 90     3 30
#                              ...
#                             8 80
#                             9 90
BEGIN {
   nb_lign = 0
}


{
    nblign += NF
    }
  for ( i=1; i <= NF ; i++) {
    tab[a+i-1]= $i
    } 
}

END{
    nb_lign = nb_lign / 2   # On doit pouvoir faire un test de parité pour détecter une erreur.
    for (a=0; a < nblign; a++) {
        print tab[a], tab[a+nblign]
    }
}

Hors ligne

#4 Le 24/01/2010, à 21:59

Zaxou

Re : [Script shell] Script d'alignement / De l'aide?

oui je sais, c'est pour ca que je l'ai précisé dans le commentaire sous le code...avec une solution proposée pour ce problème.

Il suffit pour cela de remplacer a=FN*(NR-1) par a+=FN en placant ce dernier term après le for (pour bien remplir le tableau à partir de 0). Attention, ton code ne marche pas non plus puisque la variable "a" n'est plus redéfini pour chaque ligne dans le bloc principal...

Pour ce qui est du test d'erreur, je pense qu'enregistrer le nombre de champs pour chaque ligne dans un tableau serait une bonne solution:

tab2[NR]=NF

puis dans le end comparer les valeurs de tab2[i] et tab2[i+nb_de_ligne]. D'ailleurs, il serait judicieux de remplacer nblign par nbChamp...nblign n'étant pas le nombre de lignes mais bien le nombre de champs (autant pour moi).

Pour le problème de chris_wafer il faudrait pouvoir placer le curseur ou on veux lors de l'écriture (bloc end) et ca aurait déjà pas mal avancé..."y'aurait plus qu'a" gerer ces histoires de retour à la ligne quand le pattern est trop grand.

Hors ligne

#5 Le 24/01/2010, à 22:02

boutor

Re : [Script shell] Script d'alignement / De l'aide?

Tu as raison, j'ai corrigé un peu à la va vite. big_smile

Hors ligne

#6 Le 26/01/2010, à 00:46

nesthib

Re : [Script shell] Script d'alignement / De l'aide?

(abonnement)


GUL Bordeaux : GirollServices libres : TdCT.org
Hide in your shell, scripts & astuces :  applications dans un tunnelsmart wgettrouver des pdfinstall. auto de paquetssauvegarde auto♥ awk
  ⃛ɹǝsn xnuᴉꞁ uʍop-ǝpᴉsdn

Hors ligne

#7 Le 26/01/2010, à 13:14

Totor

Re : [Script shell] Script d'alignement / De l'aide?

bonjour,
j'ai bien le sentiment que l'auteur de ce fil ne le suive pas (d'ailleurs, ça sent l'exercice) et c'est bien parceque nesthib s'y est abonné que je fourni une solution complète.

Notes :
- je sais qu'il existe une solution full bash pour connaitre la longueur d'une chaine mais les caractères accentués provoquent des erreurs
- je suis parti du principe que les patterns sont des motifs bash. Si il s'agit d'ER(E), il suffit de commenter 2 lignes et de décommenter leur équivalent
- le script prend 5 paramètres :
  + le nom du fichier contenant le texte
  + la valeur du pattern1
  + n° de colonne pour pattern1
  + la valeur du pattern2
  + n° de colonne pour pattern2

#!/bin/bash 

ajusteLongueur()
{
  if [ $# -ne 2 ]; then
    return 1
  fi
  
  typeset TEXTE="$1"
  typeset -i LONG=$2
  while [ $(awk '{print length}' <<< "${TEXTE}") -lt ${LONG} ]
  do
    TEXTE="${TEXTE} "
  done
  TEXTE="${TEXTE:0:${LONG}}"
  echo "${TEXTE}"
}

gestionPattern()
{
  ligne="$1"
  pattern="$2"
  position="$3"
#  [[ "${ligne}" =~ ${pattern} ]] && { # <-- ligne à décommenter si ER(E)
  [[ "${ligne}" = *${pattern}* ]] && { # <-- ligne à commenter si ER(E)
    debut="${ligne%%${pattern}*}" # <-- ligne à commenter si ER(E)
#   debut="$(sed "s/${pattern}.*$//" <<< "${ligne}")" # <-- ligne à décommenter si ER(E)
    fin="${ligne#${debut}}"
    [ $(awk '{print length}' <<< "${debut}") -lt $((position-1)) ] && ligne="$(ajusteLongueur "${debut}" $((position-1)))${fin}" 
    [ $(awk '{print length}' <<< "${debut}") -ge ${position} ] && {
      echo "${debut}" >&2
      ligne="$(ajusteLongueur "" $((position-1)))${fin}"
    }
  }
  echo "${ligne}"
}

FICHIER="$1"
PATTERN1="$2"
POS1="$3"
PATTERN2="$4"
POS2="$5"

{
while read ligne
do
   ligne="$(gestionPattern "${ligne}" "${PATTERN1}" "${POS1}")"
   ligne="$(gestionPattern "${ligne}" "${PATTERN2}" "${POS2}")"
   echo "${ligne}" >&2
done < "${FICHIER}" ; } 2>&1

Dernière modification par Totor (Le 26/01/2010, à 13:16)


-- Lucid Lynx --

Hors ligne

#8 Le 26/01/2010, à 14:33

nesthib

Re : [Script shell] Script d'alignement / De l'aide?

Totor a écrit :

c'est bien parceque nesthib s'y est abonné que je fourni une solution complète.

merci Totor smile je voulais y jeter un œil et je n'ai pas eu le temps hier wink.


GUL Bordeaux : GirollServices libres : TdCT.org
Hide in your shell, scripts & astuces :  applications dans un tunnelsmart wgettrouver des pdfinstall. auto de paquetssauvegarde auto♥ awk
  ⃛ɹǝsn xnuᴉꞁ uʍop-ǝpᴉsdn

Hors ligne

#9 Le 26/01/2010, à 15:06

Totor

Re : [Script shell] Script d'alignement / De l'aide?

you're welcome !
par contre, il n'est pas très optimisé...(mais fonctionnel wink)

EDIT:
Puisque le awk a été utilisé. Voici une version complète dans ce language :
Fichier align.awk:

function ajuste(texte,long) {
  while (length(texte) < long)
    texte=texte" "
  texte=substr(texte,0,long)
  return texte
}

function gestionPattern(ligne, pattern, position, vide) {
  pos=match(ligne, pattern);
  debut=substr(ligne,0,pos-1)
  fin=substr(ligne,pos)

  if (pos < position)
    ligne=substr(debut vide,0,position-1) fin

  if (pos > position)
  {
     print debut
     ligne=vide fin
  }

  return ligne
}

BEGIN {
  VIDE_1=ajuste("",(POS_1-1))
  VIDE_2=ajuste("",(POS_2-1))
}

$0 ~ PATTERN_1 { $0=gestionPattern($0, PATTERN_1, POS_1, VIDE_1) }
$0 ~ PATTERN_2 { $0=gestionPattern($0, PATTERN_2, POS_2, VIDE_2) }
/.*/

à utiliser comme ceci :
awk -v PATTERN_1="PATTERN_1" -v POS_1=26 -v PATTERN_2="PATTERN_2" -v POS_2=72 -f align.awk "nomFichier"

Dernière modification par Totor (Le 26/01/2010, à 16:47)


-- Lucid Lynx --

Hors ligne

#10 Le 28/01/2010, à 02:20

hardball

Re : [Script shell] Script d'alignement / De l'aide?

hello !
je propose un petit perl ... parce que j'adore perl

il prend en arguments : nom du fichier, pattern1, pattern2, colonne1, colonne2
il utilise le printf dont on modifie le premier argument en fonction du nombre de caractères des chaines précédentes.

perl -C -e '
($fic, $re1, $re2, $c1, $c2) = @ARGV ;
open(IN, $fic) || die "pb" ;
while(<IN>) {
    if(/^(.*?)\s*($re1.*?)\s*($re2.*)$/) {
        $e1 = ($a=split//,$1) > $c1     ? "%s\n%-".$c1."s"     : "%-".$c1."s%s" ;
        $e2 = ($a=split//,$2) > $c2-$c1 ? "%s\n%-".$c2."s%s\n" : "%-".($c2-$c1)."s%s%s\n" ;
        printf($e1.$e2,$1,"",$2,"",$3) ;
    }
}
' fichier PATTERN_1 PATTERN_2 26 72

Dernière modification par hardball (Le 28/01/2010, à 21:31)


-- Toshiba satelliteA100-335 + Ubuntu Jaunty --
Pour les noobs : Bienvenue ! ici la perséverance vous récompense.
Pour les anciens : Merci à vous de partager votre savoir.
Et vive le perl !

Hors ligne

#11 Le 29/01/2010, à 00:36

Ford Prefect

Re : [Script shell] Script d'alignement / De l'aide?

Salut à toutes et tous, hello Hardball...

Et bravo pour les subtilités, je n'avais jamais vu cette option "-C" entre autres, et la génération du format en ligne est bien vue...
Mais lancer un script ne doit pas se faire par "perl -C -e", il faut qu'il soit executable, puis:
aligner_pattern PATTERN_1 PATTERN_2 26 72
Et l'option -C ne peut pas s'ajouter à #!/usr/bin/perl

De plus ton code a oublié les '>' devant les lignes doublées.

Pour finir, j'espère que le résultat de chris_wafer est erroné et que les numérotations de lignes 1.5, 1.6 et 1.7 sont fausses. Sinon ça fera une ligne de code en plus, et ça aussi c'est fatiguant.

Je propose:

#! /usr/bin/perl
($fic, $re1, $re2, $c1, $c2) = @ARGV ;
binmode(STDOUT, ":utf8");
open(IN, "<:encoding(UTF-8)", $fic) || die "pb" ;
while(<IN>) {
    if(/^(.*?)\s*($re1.*?)\s*($re2.*)$/) {
        $e1 = (split//,$1) > $c1     ? "%s\n>%-".($c1-1)."s"     : "%-".$c1."s%s" ;
        $e2 = (split//,$2) > $c2-$c1 ? "%s\n>%-".($c2-1)."s%s\n" : "%-".($c2-$c1)."s%s%s\n" ;
        printf($e1.$e2,$1,"",$2,"",$3) ;
    }
}

On en fait un one-liner, Hardball? J'ai une vingtaine d'heures libres demain tongue

Hors ligne