6
votes

Bash - Swap Valeurs dans la colonne

J'ai des données CSV / tabular dans un fichier, comme: xxx pré>

(Ce ne sont pas toujours des chiffres, des valeurs séparées par des virgules aléatoires. Les nombres à un chiffre sont plus faciles à Un exemple, cependant.) p>

Je veux mélanger 40% de l'une des colonnes. À titre d'exemple, disons le 3ème. Donc, peut-être que 3 et 1 sont échangés les uns avec les autres. Maintenant, la troisième colonne est la suivante: p> xxx pré>

J'essaie de le faire en place dans un fichier à partir d'un script code> bash code> que je travaille sur, Et je n'ai pas beaucoup de chance. Je continue à errer de manière assez folle et infructueuse grep code> des trous de lapin qui me laissent penser que je vais avoir le mauvais sens (l'échec constant est ce qui me tire dessus). P>

i tagué cette question avec une litanie de choses parce que je ne suis pas tout à fait sûr de quel ou des outils que je devrais même utiliser pour cela. P>

EDIT: STRUT> Je vais probablement finissent par accepter la réponse de Rubens ', aussi Wacky, car elle contient directement le concept d'échange (que je suppose que j'aurais pu accentuer davantage dans la question initiale), et cela me permet de spécifier un pourcentage de la colonne pour échanger. Il arrive également de travailler, ce qui est toujours un avantage. P>

pour quelqu'un qui n'a pas besoin de cela, et veut juste un shuffle de base, la réponse de Jim Garrison fonctionne également (je l'ai testée). P>

Un mot d'avertissement, cependant, sur la solution de Rubens. J'ai pris ceci: p> xxx pré>

supprimé le printf "\ n"; code> et déplacé la nouvelle ligne de caractère comme ceci: p>

for (i = 1; i <= NF; ++i) {
  delim = (i != NF) ? "," : "\n";
  ...
}


10 commentaires

La randomisation n'est pas la force des outils de traitement de texte tels que sed ou awk .


Vous souhaitez sélectionner 40% des colonnes et mélanger complètement ceux-ci, ou sélectionnez une colonne (ou plus) et mélanger 40% de ses lignes?


Ce dernier (40% des rangées dans une colonne).


En plus de dépasser ne pas être un point fort, l'édition de lieu est totalement et totalement impossible en utilisant l'un des utilitaires marqués. Un outil externe serait requis - et les standards sont très pauvres. Vous avez besoin d'une vraie langue.


L'utilisation de SED / AWK est-elle autorisée?


@ormaaj fyi vous pouvez faire "en place édition" avec SED, Awk ou Bash. Considérez le fichier SED -I 'S / FOO / BAR /' FILE Par exemple.


Modification «in-place» signifie simplement que les détails du fichier temporaire sont manipulés pour vous. Quoi qu'il en soit, cette tâche nécessite de conserver le fichier entier en mémoire, en apportant des modifications pouvant impliquer toutes les lignes, puis la rédaction de l'écart. SED et AWK sont conçus pour traiter la ligne de ligne, sans avoir à se rappeler toutes les lignes précédant la ligne actuelle.


@Edmorton awk et bash ne peuvent certainement pas. IIRC Le responsable de GAWK ne souhaitait pas inclure une option sur place car elle n'est tout simplement pas l'outil de travail. Bash ne peut pas lsek, ce qui le rend assez impossible. Le mieux que vous puissiez faire dans Bash est des astuces comme l'ouverture d'une lecture / écriture FD, à l'aide de Lisez -n pour rechercher à droite et redéfinir la FD avec / dev / dev / fd / n pour rembobiner. Vraiment le seul shell qui a les primitives nécessaires pour ce type d'opération de fichier est ksh93 (en utilisant <# ((()) , << # , >; / Code> etc), et c'est assez douloureux, même alors.


@ORMAAJ - Pour être clair, nous ne parlons pas de réel "en place" édition (que Bash peut faire, par la manière - voir les réponses à ma récente question sur le sujet dans Comp.unix.shell) Nous parlons À propos de quelqu'un appelle un outil pour fonctionner sur un fichier d'entrée et une fois l'outil effectué en exécution, le fichier d'entrée a changé. À partir d'un point de vue des utilisateurs, il est fonctionnellement équivalent à une édition «in-place» true et l'un des outils que j'ai mentionnés peut faire cela. Misté: GAWK obtiendra une option d'édition sur place spécifique GAWK -IINPLACE , équivalent fonctionnellement à SED -I , dans une version à venir.


@Edmorton qui serait une sorte de gentille. Au moins AWK fournit un moyen sûr d'injecter des variables de shell. SED -I est tout simplement très inadéquat. Je me penche vers l'utilisation de Python (comme le module MMAP et de belles abstractions telles que MemoryView) ou un script VIM, jusqu'à ce que peut-être un jour, quelqu'un écrit et standardise un éditeur non interactif décent à mi-chemin. Bien que je supporterai mon commentaire à propos de Bash, même avec des fichiers temporaires. Cela fait longtemps que j'ai vu une nouvelle technique de manipulation de fichiers intéressante.


3 Réponses :


4
votes

Cela fonctionnera pour une colonne spécifiquement désignée, mais devrait suffire à vous pointer dans la bonne direction. Cela fonctionne sur des coquilles de bash modernes, y compris Cygwin: xxx

la fonctionnalité opératoire est " Substitution de processus ".

La commande La commande joint des fichiers horizontalement et les trois pièces sont scindées du fichier d'origine via Cut , avec la deuxième pièce (la colonne à aléomiser) exécutée via la commande shuf pour réorganiser les lignes. Voici la sortie de l'exécution plusieurs fois: xxx


1 commentaires

+1 shuf doit probablement être remplacé par un shuffler personnalisé pour gérer la contrainte de 40%, mais sinon agréable (en supposant un nombre fixe de colonnes).



1
votes

algorithme fort>:

  • Créez un vecteur avec n code> paires, à partir de 1 code> à Nombre de lignes code> et la valeur correspondante dans la ligne (pour la colonne sélectionnée ), puis triez-la au hasard; li>
  • Trouvez combien de lignes doivent être randomisées: num_random = pourcentage * num_lines / 100 code>; li>
  • Sélectionnez le premier num_random code> Entrées de votre vecteur randomisé; Li>
  • Vous pouvez trier les lignes sélectionnées au hasard, mais il devrait être déjà trié au hasard; Li>
  • sortie d'impression: p>

    $ ./script.sh infile 3 40
    1,7,3,2
    8,3,8,0
    4,9,1,3
    8,5,7,3
    5,6,5,9
    


0 commentaires

0
votes

J'utiliserais une approche de 2 passes qui commence par avoir un nombre de lignes et lisez le fichier dans un tableau, puis utilisez la fonction RAND () d'AWK () pour générer des numéros aléatoires pour identifier les lignes que vous modifiez. et ensuite rand () à nouveau pour déterminer quelles paires de ces lignes vous échangeront puis échangez les éléments de la matrice avant d'imprimer. Quelque chose comme ce pseudo-code, algorithme rugueux: xxx


0 commentaires