J’essaie de comprendre comment créer un fichier .txt (myGeneFile.txt) d’ID et de gènes ressemblant à ceci:
Probe Set ID Gene Symbol 1007_s_at DDR1 /// MIR4640 1053_at RFC2 117_at HSPA6 121_at PAX8 1255_g_at GUCA1A 1294_at MIR5193 /// UBA7
dans ceci:
DDR1 MIR4640 RFC2 HSPA6 PAX8 GUCA1A MIR5193 UBA
J’ai d’abord essayé de faire ça:
cat myGeneFile.txt | tail -n +2 | awk '{split($2,a,"///"); print a[1] "\t" a[2] "\t" a[3] "\t" a[4] "\t" a[5];}' > test.txt
(c.-à-d., j’ai supprimé la ligne supérieure (en-tête) du fichier, j’ai essayé de diviser la deuxième ligne le long du délimiteur ///, puis d’imprimer tous les gènes qui pourraient apparaître)
Ensuite, j’ai essayé de faire ceci:
cat myGeneFile.txt | tail -n +2 | awk '{print $2}' | grep -o -E '\w+' > test.txt
(listant littéralement tous les mots de la deuxième colonne)
J’ai obtenu le même résultat dans les deux cas – une longue liste de seulement le premier gène dans chaque ligne (par exemple, MIR4640 et UBA7 étaient mal alignés)
Des idées?
EDIT: Merci @CodeGnome pour votre aide. J’ai fini par utiliser ce code et je l’ai modifié car j’ai découvert que mon fichier contenait entre 1 et 30 noms de gènes différents sur chaque ligne. Donc, j’ai utilisé:
awk 'NR == 1 {next} { sub("///", "") print $2 } { for (i=3; i test2.txt
@GlenJackson avait aussi une solution qui fonctionnait très bien:
awk 'NR>1 {for (i=2; i<=NF; i++) if ($i != "///") print $i}' file
Mon awk prend:
awk 'NR>1 {for (i=2; i<=NF; i++) if ($i != "///") print $i}' file
ou sed
sed ' 1d # delete the header s/[[:blank:]]\+/ /g # squeeze whitespace s/^[^ ]\+ // # remove the 1st word s| ///||g # delete all "///" words s/ /\n/g # replace spaces with newlines ' file
Ce qui suit donne la sortie souhaitée en supprimant les caractères indésirables avec sub (), puis en utilisant plusieurs instructions d’impression pour créer les sauts de ligne. La deuxième instruction d’impression est conditionnelle et ne se déclenche que lorsque le troisième champ n’est pas vide. Cela évite de créer des lignes vides dans la sortie.
$ awk 'NR == 1 {next} { sub("///", "") print $2 if ($3) {print $3} }' myGeneFile.txt DDR1 MIR4640 RFC2 HSPA6 PAX8 GUCA1A MIR5193 UBA7
Cela fonctionnera:
tail -n+2 tmp | sed -E 's/ +/ /' | cut -d' ' -f2- | sed 's_ */// *_\n_'
Voici ce qui se passe:
tail -n+2
Enlève l’en-tête sed -E 's/ +/ /'
Condense les espaces cut -d' ' -f2-
Utilisez cut pour sélectionner tous les champs sauf le premier, en utilisant un seul espace comme délimiteur sed 's_ */// *_\n_'
Convertit tous les ///
(et tout espace blanc environnant) en une nouvelle ligne Vous n’avez pas besoin du cat
initial, il est généralement préférable de simplement passer le fichier d’entrée en tant qu’argument à la première commande. Si vous voulez le nom du fichier dans un endroit facile à modifier, cette option est préférable car elle évite le processus supplémentaire (et je trouve plus facile de changer le fichier à la fin):
(tail -n+2 | sed -E 's/ +/ /' | cut -d' ' -f2- | sed 's_ */// *_\n_') < tmp
Compte tenu de l’entrée existante et de l’exigence modifiée (d’après le commentaire de la réponse de Morgen), ce qui suit devrait faire ce que vous voulez (pour un nombre quelconque de colonnes de gènes).
awk 'NR > 1 { p=0 for (i = 2; i <= NF; i++) { if ($i == "///") { p=1 continue } printf "%s%s\n", p?"n":"", $i } }' input.txt
Vos critères pour sélectionner les chaînes à sortir ne sont pas tout à fait claires, mais voici une autre commande qui produit au moins votre sortie attendue:
tail -n +2 myGeneFile.txt | grep -oE '\<[AZ][A-Z0-9]*\>'
Il ne fait que 1) sauter la première ligne et 2) trouver tous les autres mots (délimités par des caractères non-mots et / ou début / fin de ligne) qui sont entièrement composés de lettres majuscules ou de chiffres, le premier étant une lettre.