J'ai un fichier ( data.rdb
) au format suivant:
date star jdb texp 2013-11-22#epsInd#2400000.23551544#100.
Certaines propriétés des données:
J'ai besoin d'extraire certaines des colonnes par nom en utilisant bash, par exemple, col1
, col3
et col6
, où les colonnes à sélectionner proviennent d'une variable shell définie comme COLUMN_LIST = $ @
où $ @
sont les paramètres passés à mon script shell. Le nombre et le nom des paramètres peuvent changer chaque fois que j'appelle le script.
Le script doit être en bash, ne peut pas être python ou similaire.
Des idées? J'ai pensé à utiliser awk
/ gawk
, mais je ne sais pas comment sélectionner par nom de colonne. L'ordre des colonnes peut changer d'un fichier à l'autre.
Merci Jorge
MISE À JOUR
pour une raison quelconque, aucune de ces solutions ne semble fonctionner sur mes vrais fichiers de données (c'est-à-dire que je n'obtiens aucun résultat), donc je poste un sous-ensemble de l'un de ceux-ci:
tr $'\t' '#' < data.rdb | head -2
dans ce cas, je serais intéressé par les colonnes star
jdb code> et
texp
MISE À JOUR 2
J'ai utilisé le code de @ EdMorton et voici le résultat: p >
BEGIN { numCols = split(column_list,cols) OFS="\t" } { sub(/\r$/,"") } NR==1 { for (fldNr=1; fldNr<=NF; fldNr++) { f[$fldNr] = fldNr } } { for (colNr=1; colNr<=numCols; colNr++) { colName = cols[colNr] colVal = (colName in f ? $(f[colName]) : "") printf "%s%s", colVal, (colNr<numCols ? OFS : ORS) } }
UPDATE 3
J'ai fini par utiliser la version d'EdMorton de awk
- principalement pour la flexibilité sur le sortie - mais avec la modification que je ne veux pas qu'il affiche de mauvaises colonnes:
date star jdb texp date star jdb texp 2013-11-22 epsInd 2400000.23551544 100. 2013-11-22 epsInd 2400000.23551544 100. 2013-11-22 epsInd 2400000.23551544 100. 2013-11-22 epsInd 2400000.23551544 100. 2013-11-22 epsInd 2400000.23551544 100. 2013-11-22 epsInd 2400000.23551544 100. 2013-11-22 HD217987 2400000.23551544 900. 2013-11-22 HD217987 2400000.23551544 900. 2013-11-22 TOI-134 2400000.23551544 900. 2013-11-22 TOI-134 2400000.23551544 900. 2013-11-22 tauCet 2400000.23551544 60. 2013-11-22 tauCet 2400000.23551544 60. 2013-11-22 BD+01316 2400000.23551544 300. 2013-11-22 BD+01316 2400000.23551544 300. 2013-11-22 BD+01316 2400000.23551544 300. 2013-11-22 BD+01316 2400000.23551544 300. 2013-11-22 BD+01316 2400000.23551544 300. 2013-11-22 BD+01316 2400000.23551544 300. 2013-11-22 BD+01316 2400000.23551544 300. 2013-11-22 BD+01316 2400000.23551544 300.
Le principal problème que j'ai eu était que la ligne d'en-tête n'était pas séparée par des tabulations et en tant que telle la ventilation des colonnes n'a pas fonctionné. Un moyen facile de repérer les caractères de tabulation / non-tabulation:
date star jdb texp 2013-11-22 epsInd 2400000.23551544 100. 2013-11-22 epsInd 2400000.23551544 100. 2013-11-22 epsInd 2400000.23551544 100. 2013-11-22 HD217987 2400000.23551544 900. 2013-11-22 TOI-134 2400000.23551544 900. 2013-11-22 tauCet 2400000.23551544 60. 2013-11-22 BD+01316 2400000.23551544 300. 2013-11-22 BD+01316 2400000.23551544 300. 2013-11-22 BD+01316 2400000.23551544 300. 2013-11-22 BD+01316 2400000.23551544 300.
qui a donné sur l'un de mes fichiers de test:
col1 col2 col3 col4 col5 col6 col7 aaa1 bbb1 ccc1 ddd1 eee1 fff1 ggg1 aaa2 bbb2 ccc2 ddd2 eee2 fff2 ggg2 aaa3 bbb3 ccc3 ddd3 eee3 fff3 ggg3
p>
3 Réponses :
L'ordre des colonnes peut changer d'un fichier à l'autre.
Vous pouvez utiliser cette approche en utilisant
awk
qui prend les noms de colonnes d'en-tête séparés par des espaces en entrée et les convertit d'abord en numéro de colonne en traitant le premier enregistrement. Une fois les numéros de colonne requis récupérés, nous les imprimons simplement à partir de la ligne suivante.star jdb texp epsInd 2400000.23551544 100. epsInd 2400000.23551544 100. epsInd 2400000.23551544 100. HD217987 2400000.23551544 900. TOI-134 2400000.23551544 900. tauCet 2400000.23551544 60. BD+01316 2400000.23551544 300. BD+01316 2400000.23551544 300. BD+01316 2400000.23551544 300. BD+01316 2400000.23551544 300.
awk -v cols='col1 col3 col6' 'BEGIN { FS=OFS="\t" n = split(cols, a, " ") for (i=1; i <= n; i++) c[a[i]] } { sub(/\r$/, "") } NR == 1 { for (i=1; i<=NF; i++) if ($i in c) hdr[i] } { for (i=1; i<=NF; i++) if (i in hdr) s = sprintf(s "%s%s", OFS, $i) sub(OFS, "", s) print s s ="" } ' file | column -tPS: Ajout de
column -t
pour formater la sortie au format tabulaire.
Merci, mais je n'arrive pas à le faire fonctionner sur mes fichiers. Une note, les vraies colonnes sont des notes nommées "colX" mais ont des noms totalement différents, tels que rv
, fwhm
, etc., cela ferait-il une différence?
@jorgehumberto: Vérifiez la réponse mise à jour avec votre entrée nouvellement mise à jour
Vous pouvez le faire avec coreutils
. En supposant que vous ayez un fichier callef cols
contenant les colonnes souhaitées, par exemple:
col2 col3 col6 bbb1 ccc1 fff1 bbb2 ccc2 fff2 bbb3 ccc3 fff3
Vous pouvez extraire les numéros de colonne comme ceci:
cut -f $(head -n1 infile | tr '\t' '\n' | grep -nf cols | cut -d: -f1 | paste -sd,) infile
quel est le format de cols?
un fichier ou une variable shell?
La meilleure façon de gérer cela est de créer un tableau ( f []
ci-dessous) qui mappe les chaînes d'en-tête de colonne (c'est-à-dire les noms de champ) aux numéros de champ lors de la lecture de la ligne d'en-tête et puis accédez aux champs par leur nom à partir de là.
Mise à jour pour se protéger contre l'appelant demandant un nom de colonne qui n'existe pas et contre les fins de ligne DOS:
$ awk -v column_list='col5 col2 col4' -f tst.awk data.rdb col5 col2 col4 eee1 bbb1 ddd1 eee2 bbb2 ddd2 eee3 bbb3 ddd3
Notez qu'avec l'approche ci-dessus, si vous le souhaitez, vous pouvez modifier l'ordre des colonnes de sortie, pas simplement les imprimer dans leur ordre d'origine:
$ cat tst.awk BEGIN { numCols = split(column_list,cols) FS=OFS="\t" } { sub(/\r$/,"") } NR==1 { for (fldNr=1; fldNr<=NF; fldNr++) { f[$fldNr] = fldNr } } { for (colNr=1; colNr<=numCols; colNr++) { colName = cols[colNr] colVal = (colName in f ? $(f[colName]) : (NR>1 ? "N/A" : colName)) printf "%s%s", colVal, (colNr<numCols ? OFS : ORS) } } $ awk -v column_list='col1 col3 col6' -f tst.awk data.rdb col1 col3 col6 aaa1 ccc1 fff1 aaa2 ccc2 fff2 aaa3 ccc3 fff3 $ awk -v column_list='col1 col3 col6 bob' -f tst.awk data.rdb col1 col3 col6 bob aaa1 ccc1 fff1 N/A aaa2 ccc2 fff2 N/A aaa3 ccc3 fff3 N/A
ok, j'ai réussi à faire fonctionner ce qui précède, il suffit d'échanger FS = OFS = "\ t"
par OFS = "\ t"
.
Vous avez dit dans votre question que toutes les colonnes sont séparées par des tabulations
. Si vous ne deviez pas définir FS sur tabulation pour que cela fonctionne, cette affirmation n'est pas vraie, ce qui expliquerait certainement pourquoi vous ne pouvez pas faire fonctionner l'une des solutions que nous avons fournies sur la base de cette déclaration.
C'est la chose étrange, j'ai revérifié mes fichiers de données et les séparateurs semblent être des onglets
(ou au moins montrer comme onglet
lorsque je les sélectionne sur la ligne de commande ..).
Et je les ai générés sous forme d'onglets. Lorsque je crée les fichiers avec awk
(code adapté de stackoverflow.com/questions/25168259/... ) I assurez-vous que OFS = "\ t" est défini.
Exécutez tr $ '\ t' '#'
ok, le problème semble être avec les en-têtes, désolé à ce sujet.line1: date star jdb texp
line2: 2013-11-22 # epsInd # 2400000.23551544 # 100.
Comment appelez-vous votre script? Comme
./myscript 1 3 6
ou./myscript colname1 colname2 colname3
@kvantour:
./myscript colname1 colname2
désolé, par tout ce que je veux dire, un mot, j'ai mis à jour la question.
Ils sont en effet séparés par des tabulations et ne semblent pas trouver de problème avec eux.
La seule différence que je peux trouver est que j'ai beaucoup plus de lignes et plus de colonnes
Je soupçonne fortement que votre fichier d'entrée a des fins de ligne DOS, voir stackoverflow.com/q/45772525/1745001 pour ce que cela signifie et comment le réparer. Pendant ce temps, j'ai mis à jour ma réponse pour me protéger contre les fins de ligne DOS et / ou un utilisateur demandant un nom de colonne qui n'existe pas pour être affiché. Essayez-le maintenant et dites-nous le résultat.
Ok, j'ai vérifié quelques fichiers avec
cat -vE
et la seule chose étrange que j'obtiens sont des signes dollar à la fin de chaque ligne ... L'exécution de votre version mise à jour du code me permet les en-têtes de colonne (s) correct (s), cependant tous remplis avec N / A.Les signes
$
indiquent le caractère de saut de ligne. Ils sont normaux / attendus à la fin de chaque ligne. D'après votre autre commentaire, il semble que vos colonnes ne soient PAS séparées par des tabulations comme vous l'avez affirmé et c'est votre problème. Pour la prochaine fois - vous auriez pu le repérer en exécutanttr $ '\ t' '#' pour rendre les onglets visibles.
c'est une bonne commande à garder, merci! Quand je l'exécute, j'obtiens
#
à la place des onglets, mais des espaces dans les en-têtes, bien que je crée mes en-têtes avec `header = $ (echo date $ '\ t'star $' \ t ' rv $ '\ t'dvrms $' \ t '). Pourquoi en est-il ainsi?Vous êtes les bienvenus. Vous n'avez pas cité la chaîne que vous avez passée à echo, donc echo a vu chaque valeur séparée par des tabulations comme un argument séparé et les a sorties séparées par des blancs. Essayez simplement
header = $ 'date \ tstar \ trv \ tdvrms'
à la place.ok, merci, va corriger mon code en tenant compte de cela, merci!