1
votes

Réorganiser les champs du nième au NF-1 avec awk

Mon problème: J'ai un fichier d'entrée de délimiteur de tuyaux et je dois d'abord mettre la dernière colonne, déposer la deuxième et imprimer du troisième au dernier-1.

Actuellement, cela fonctionne avec mon fichier à 7 champs:

while read line
do
        echo -n "$line|"
        echo -n  $line | cut -d'|' -f1 | sed "s/\"//g" | tr -d '\n' | sha256sum | cut -d' ' -f1
done < $f_x_file_name.$f_x_file_extension > $f_x_file_name.hash.$f_x_file_extension ;

Mais je cherche quelque chose de plus automatique, qui fonctionne avec n nombre de colonnes

J'ai essayé une boucle, mais il imprime tous les champs sur une ligne séparée.

6440bc7a8f41a96f89ee123159b7eb819a99767c9107b24e9d346eb3835f74a7|2017-09-08T09:46:40.000|"AUDIOTEL"|"Virement +"|25|"50747071"
cd558b1319595aa63929d8cf3d8213ccc004aac089e6dd3bbad1d595ad010335|2020-02-11T10:02:20.000|"WEB"|"Virement +"|25|"51254683"
f128a559267df0f9a6352fb40f65594aa8f5d01d5c3b90f471ffa0be07739c4d|2019-07-03T12:00:00.000|"WEB"|"Virement +"|195|"51080106"

Mais ceci imprime tous les champs sur des lignes séparées, plus le premier n'est pas imprimé.

J'ai essayé beaucoup d'autres solutions mais pas de chance jusqu'à présent .. .

Y a-t-il une option qui me manque?

Entrée:

"PRILYYYTVENIZKEB@XXXX"|2017-09-08T09:46:40.000|"AUDIOTEL"|"Virement +"|25|"50747071"|6440bc7a8f41a96f89ee123159b7eb819a99767c9107b24e9d346eb3835f74a7
"CSRBQDVXJEFPACTKOO@AAA"|2020-02-11T10:02:20.000|"WEB"|"Virement +"|25|"51254683"|cd558b1319595aa63929d8cf3d8213ccc004aac089e6dd3bbad1d595ad010335
"WOGMKZLBHDFPACTKHG@ZZZZ"|2019-07-03T12:00:00.000|"WEB"|"Virement +"|195|"51080106"|f128a559267df0f9a6352fb40f65594aa8f5d01d5c3b90f471ffa0be07739c4d

Attendue:

awk 'BEGIN { FS="|"; OFS="|"; } {for(i=2;i<=NF-1;++i)print $i}'

(l'e-mail du 2ème est supprimé et le hachage du dernier est mis en premier).


Contexte global (peut-être qu'une autre solution plus directe est possible): p >

Mon objectif est de remplacer le premier champ par une valeur calculée par hachage de ce champ.

J'utilise un fichier temporaire pour ajouter mon champ calculé à la fin de mon fichier:

awk 'BEGIN { FS="|"; OFS="|"; } {print $NF,$2,$3,$4,$5,$6}'

Merci!

Cordialement


2 commentaires

Veuillez publier des exemples de données avec la sortie attendue, modifier le message d'origine, ne pas publier en tant que commentaire.


J'ai posté une réponse à la question que vous avez posée en premier sur la façon d'échanger des champs. Si vous souhaitez une meilleure façon de remplacer le premier champ par une valeur calculée par hachage de ce champ. comme indiqué à la fin de votre question, jetez un œil à stackoverflow.com/a/53762874/1745001 et postez une autre question, toujours avec un exemple d'entrée / sortie, si vous avez besoin d'aide.


4 Réponses :


2
votes

Si je comprends bien ce que vous entendez par:

mettez la dernière colonne en premier, déposez la deuxième et imprimez à partir de la troisième au dernier-1

alors une manière plus concise de dire ce serait:

déplacer la première colonne vers la deuxième et déplacer la dernière colonne vers la première

qui serait:

$ echo 'a|b|c|d' | awk 'BEGIN{FS=OFS="|"} {$2=$1; $1=$NF; NF--} 1'
d|a|c

par exemple:

awk 'BEGIN{FS=OFS="|"} {$2=$1; $1=$NF; NF--} 1' file

Utilisation de NF- - pour supprimer la dernière colonne est un comportement non défini par POSIX, si votre awk ne le prend pas en charge alors changez simplement NF-- en sub (/ \ | [^ |] * $ /, "") .

Si j'ai mal compris ce que vous essayez de faire, modifiez votre question pour fournir un exemple d'entrée concis et testable et le résultat attendu.

p>


6 commentaires

Un folklore sur lequel awks ne supporte pas NF-- ? Je suis tombé sur une situation similaire plus tôt dans la journée, j'ai décidé de le tester sur quelques awks mais ils l'ont tous fait. Je l'ai sûrement vu échouer mais je ne me souviens plus de quel awk il s'agissait.


@JamesBrown Non, désolé, mais si j'avais accès à l'un ou l'autre, je testerais nawk et / usr / xpg4 / bin / awk sur Solaris.


@JamesBrown Je viens de l'essayer sur MacOS ( / usr / bin / awk --version -> awk version 20070501 ) et echo '1 2 3' | / usr / bin / awk '{NF -} 1' affiche 1 2 3 . gawk sur la même boîte sort 1 2 . Intéressant echo '1 2 3' | / usr / bin / awk '{$ 1 = $ 1; NF -} 1 ' génère également 1 2 donc ce que fait NF-- ne dépend pas seulement de la version de awk que vous utilisez mais aussi sur ce que vous faites d'autre dans votre script awk spécifique - je suppose que c'est pourquoi ils appellent le comportement "indéfini" :-).


Ouais ok, je vois ça avec l'original-awk de Debian, awk version 20121220 , aussi (mais pas dans la awk version 20200625 que je viens de rencontrer). Merci Monsieur.


Merci de répondre ! Cette commande fournit ce que j'attendais: awk 'BEGIN {FS = OFS = "|"} {$ 1 = $ NF; NF--} 1 '


De rien. Consultez stackoverflow.com/help/someone-answers pour savoir ce qu'il faut faire ensuite.



0
votes

basé sur le script, pas sur votre description, vous voulez

$ seq 5 | paste -sd'|' | awk 'BEGIN{FS=OFS="|"} {$1=$NF; NF--}1'
5|2|3|4

exemple:

awk 'BEGIN{FS=OFS="|"} {$1=$NF; NF--}1' file


0 commentaires

0
votes

Alors que dans la situation actuelle, cela est facilement implémenté, je me demande toujours pourquoi il n'y a pas de fonction concat qui effectue l'opération inverse de split :

  • split (s, a [ fs]) : Divise la chaîne s en éléments de tableau a [ 1], a [2], ..., a [n] et renvoie n . Tous les éléments du tableau doivent être supprimés avant que le fractionnement ne soit effectué. La séparation doit être faite avec l'ERE fs ou avec le séparateur de champ FS si fs n'est pas donné. Chaque élément de tableau doit avoir une valeur de chaîne lors de sa création et, le cas échéant, l'élément de tableau doit être considéré comme une chaîne numérique (voir Expressions dans awk). L'effet d'une chaîne nulle en tant que valeur de fs n'est pas spécifié.

  • concat (a [ ofs]) : Concatène les éléments du tableau a [1], a [2], ..., a [n] avec ofs comme séparateur de champ ou OFS si ofs n'est pas donné. Les valeurs de chaînes numériques sont converties en chaînes à l'aide de CONVFMT . Les premiers éléments du tableau n sont concaténés, où n + 1 dans un renvoie 0.

L'implémentation de concat se lirait comme suit:

BEGIN{FS=OFS="|"}
{ n=split($0,a) }
{ a[2]=a[1]; a[1]=a[n]; delete a[n] }
{ print concat(a) }

En utilisant cette fonction, vous pourriez facilement créer un tableau avec des éléments et assemblez-le comme une chaîne de champs:

function concat(a,  ofs,  s,i) {
     ofs=(ofs=="" && ofs==0 ? OFS : ofs)
     i=1; while(i in a) { s = s (i==1?"":ofs) a[i]; i++ }
     return s
}

Voir les commentaires ci-dessous pour plus d'informations à ce sujet.


6 commentaires

La raison pour laquelle il n'y a pas de fonction concat est qu'elle est facile à faire avec d'autres constructions (principe majeur du langage awk pour éviter le gonflement du langage - ne fournir que des constructions pour les tâches difficiles à faire avec d'autres constructions) et une version de celle-ci qui concatène uniquement les tableaux avec l'incrémentation d'indices numériques sans lacunes serait d'une utilité limitée alors qu'une version générique de celui-ci devrait prendre en compte le type d'indices et l'ordre dans lequel les éléments du tableau doivent être visités. C'est l'une des nombreuses choses que je souhaite aussi parfois awk avait mais comprenez pourquoi ce n'est pas le cas.


Dans un concat () btw fourni, il devrait y avoir un moyen de spécifier qu'aucun séparateur ne doit être utilisé donc ofs = (ofs == ""? OFS: ofs) devrait être modifié en. ofs = ((ofs == "") && (ofs == 0)? OFS: ofs) donc ofs est uniquement défini sur OFS si la fonction est appelée sans argument ofs . À mon humble avis, cela ne vaut pas la peine de s'inquiéter, je pensais juste que cela valait la peine de souligner l'un des détails qui devraient être traités si une fonction concat () allait fournir.


et oui étant donné foo (arg) {... if ((arg == "") && (arg == 0)) ...} est la façon dont vous testez pour un argument de fonction optionnel n'étant pas présente car seules les variables non initialisées (y compris les arguments de fonction) ont la valeur zéro ou nul.


@EdMorton Merci pour votre précieuse contribution. Je n'ai jamais pensé à tester à la fois zéro et une chaîne vide pour vérifier si un argument est disponible ou non.


FWIW en haut de ma liste de souhaits pour awk serait un seul indicateur pour définir les séparateurs de champ d'entrée et de sortie. Dans mon monde parfait, nous aurions IFS pour le séparateur de champ d'entrée, OFS pour le séparateur de champ de sortie et FS (qui peut être défini avec -F ) pour les deux séparateurs de champs (donc awk -F, ... définirait FS, ce qui signifie maintenant les séparateurs de champs d'entrée et de sortie à , au lieu de awk -F, -v OFS =, ... ou similaire) qui peut être remplacé en définissant également l'un ou l'autre. Mais je ne vais pas retenir mon souffle :-).


@EdMorton Oui, je ne sais pas combien de fois j'écris BEGIN {FS = OFS = "x"}



0
votes

Modifiez le script dans lequel vous calculez le hachage.

while IFS='|' read -r firstfield otherfields
do
   hash=$(sha256sum <<< "${firstfield}" | cut -d' ' -f1)
   echo "${hash}|${otherfields}"
done < "$f_x_file_name"."$f_x_file_extension" > "$f_x_file_name".hash."$f_x_file_extension" 

ou encore plus simple:

while read -r line
do
   # hash from your command:
   # hash=$(echo -n  $line | cut -d'|' -f1 | sed "s/\"//g" | tr -d '\n' | 
   #        sha256sum | cut -d' ' -f1)
   # Slightly changed
   hash=$(cut -d'|' -f1 <<<"${line}"| tr -d '\n"' | sha256sum | cut -d' ' -f1)
   echo "${hash}|$(cut -d '|' -f2- <<< "${line}")"
done < "$f_x_file_name"."$f_x_file_extension" > "$f_x_file_name".hash."$f_x_file_extension" 


0 commentaires