2017-06-04 3 views
2

Est-ce que quelqu'un connaît un oneliner dans lequel une sortie peut être transmise en bash, pour faire correspondre et convertir toutes les occurrences de nombres hexadécimaux et laisser tous les autres textes intacts?bash: oneliner pour convertir les nombres hexadécimaux en nombres décimaux

  • correspondent peut-être la production plutôt arbitraire qui pourrait être un hexadécimal est en quelque sorte converti par une expression rationnelle, à savoir /(0x)?[0-9a-fA-F]{5,}/
  • un des principaux 0x ne doit pas être neccessary, mais également être manipulé correctement
  • il peut y avoir faux-positifs, sinon spécifiant une longueur minimale des nombres, mais cela ne devrait pas être un numéro
  • le but est de trouver une solution qui peut être utilisée avec ette sorties possibles ayant des nombres hexadécimaux dans les

Il devrait fonctionner sur la production comme:

ssg sjas # cat /proc/net/stat/arp_cache | column -t 
entries allocs destroys hash_grows lookups hits  res_failed rcv_probes_mcast rcv_probes_ucast periodic_gc_runs forced_gc_runs unresolved_discards table_fulls 
0000000d 00000006 00000004 00000000 0000c3b9 0000c35e 00000000 00000000   00000000   0000965b   00000000  00000000    00000000 
0000000d 0000000d 00000004 00000001 00000000 00000000 00000000 00000000   00000000   000007cd   00000000  00000000    00000000 
0000000d 00000008 00000008 00000001 00000000 00000000 00000000 00000000   00000000   000006e0   00000000  00000000    00000000 
0000000d 0000000a 00000008 00000000 00000000 00000000 00000002 00000000   00000000   00000704   00000000  00000000    00000000 

La plupart des autres questions sur StackOverflow ne s'attaquer à la question de savoir comment convertir des nombres simples entre les systèmes numériques, seulement faire la conversion pour une colonne spécifiée ou complètement tuer le formatage étant présent dans l'entrée.

sortie désiré devrait ressembler à: (column -t est là de toute façon, il a vraiment juste besoin de remplacer les valeurs hexa qu'il peut trouver, et en ajoutant des zéros à une instruction printf est pas non plus un problème)

ssg sjas # cat /proc/net/stat/arp_cache | perl -pe 's/(?:0x)?[0-9a-f]{5,}/hex($&)/ge' | column -t 
entries allocs destroys hash_grows lookups hits res_failed rcv_probes_mcast rcv_probes_ucast periodic_gc_runs forced_gc_runs unresolved_discards table_fulls 
13  6  4   0   50105 50014 0   0     0     38491    0    0     0 
13  13  4   1   0  0  0   0     0     1997    0    0     0 
13  8  8   1   0  0  0   0     0     1760    0    0     0 
13  10  8   0   0  0  2   0     0     1796    0    0     0 

Je n'ai pas pu trouver une solution viable/fiable via sed/awk/perl dans les deux dernières heures, alors je suis venu ici pour obtenir de l'aide.

+0

S'il vous plaît ajouter votre sortie désirée pour cet exemple d'entrée à votre question. – Cyrus

+0

@Cyrus a fait cela. – sjas

+0

La sortie désirée ne correspond pas à l'entrée, pourquoi '0000c1c5' est-il converti en' 0'? – 123

Répondre

3

perl en utilisant le drapeau de e à substitution

perl -pe 's/(0x)?[0-9a-f]{5,}/hex $&/ge' file | column -t 
-1

Un 0 de premier rang est considéré comme octal et un 0x de premier rang est considéré comme hexadécimal. Si vos chiffres sont conformes à cette norme, alors $((<number>)) les convertit en décimal:

$ echo $((0x1b)) 
27 
$ echo $((014)) 
12 
+0

Il ne s'agissait pas explicitement de convertir des nombres solitaires mais de produire des résultats complets. – sjas

0

avec GNU awk:

awk 'BEGIN{IFS=OFS="\t"}NR==1{print $0}{for(i=1;i<=NF;i++) if(i!=NF){printf "%s%c",strtonum("0x"$i),OFS}else{printf "%d\n",strtonum("0x"$i)}}' filename 
+0

Ceci est assez similaire à ce que j'ai déjà eu, mais ne fonctionne pas comme prévu. C'est à dire. '0000000d' est converti en' 0' au lieu de '13'. – sjas

+0

Oui. j'ai édité. – tso

2

perl avec le commutateur autosplit:

perl -anE'say join " ", map {/(?:0x)?([0-9a-f]{5,})/i ? hex $1 : $_} @F' file | column -t 

-n fournit une boucle implicite sur les lignes du fichier.

Le commutateur -E met à disposition des fonctionnalités optionnelles telles que la commande say(utile pour imprimer quelque chose avec un retour chariot automatique). -E fait aussi la même chose que le commutateur -e qui exécute le code donné dans le paramètre (au lieu de chercher un fichier à lancer).

Le commutateur -a (autosplit) divise chaque ligne sur les espaces et remplit le tableau @F avec les pièces (comme awk).

map { } @F traite chaque élément de @F et renvoie un nouveau tableau.

/(?:0x)?([0-9a-f]{5,})/i ? hex($1) : $_ utilise l'opérateur ternaire condition ? true : false. Lorsque le motif correspond, il renvoie le groupe de capture 1 converti, lorsqu'il ne contient pas la pièce d'origine.

Notez que Perl est une langue qui prend en compte le contexte. $_ à l'intérieur du map {} fait référence à un article @F, et /(?:0x)?([0-9a-f]{5,})/i est la version courte pour $_ =~ /(?:0x)?([0-9a-f]{5,})/i. (en dehors de la map {}$_ est la ligne courante)

+0

Nice, cela fonctionne! Merci beaucoup. – sjas

+0

@sjas: no my fault @ 123 réponse correcte puisque 'print hex" 0x10 "' * (cité cette fois) * renvoie '16' comme prévu. Vous devriez accepter sa réponse qui est plus courte au lieu de la mienne –

+0

@CasimiretHippolyte: Merci pour le bon code, pourriez-vous s'il vous plaît ajouter une explication à cela aussi, je suis un débutant en perl. – RavinderSingh13

1

Avec mawk: pour chaque ligne mais première boucle rangée (NR!=1) de la première à la dernière colonne (NF) et convertir la colonne actuelle ($i) d'hex en décimal.

mawk 'NR!=1 {for (i=1; i<=NF; i++) $i=sprintf("%d ","0x"$i)}1' file | column -t 

Sortie:

 
entries allocs destroys hash_grows lookups hits res_failed rcv_probes_mcast rcv_probes_ucast periodic_gc_runs forced_gc_runs unresolved_discards table_fulls 
13  6  4   0   49696 49605 0   0     0     38201    0    0     0 
13  13  4   1   0  0  0   0     0     1984    0    0     0 
13  8  8   1   0  0  0   0     0     1752    0    0     0 
13  10  8   0   0  0  2   0     0     1775    0    0     0 
1

Désolé pour la confusion. Voici un one-liner qui utilise cette fonctionnalité de bash:

cat /proc/net/stat/arp_cache | sed -e '2,$s/\s*\([0-9a-f][0-9a-f]*\)\s*/ \$\(\(0x\1 \)\) /g' -e 's/^/echo /' | bash | column -t 
entries allocs destroys hash_grows lookups hits res_failed rcv_probes_mcast rcv_probes_ucast periodic_gc_runs forced_gc_runs unresolved_discards table_fulls 
8  2  0   0   0  0  0   0     0     0     0    0     0 
8  0  0   0   211  58 0   0     0     0     0    0     0 
8  2  0   0   6319  1677 0   0     0     3882    0    0     0 
8  4  0   0   4731  1299 0   0     0     0     0    0     0 
+1

Oooooo !!! Moi j'aime! Je l'ai réparé. Merci! – Jack

+0

Vous avez ajouté une autre réponse et ajouté un commentaire vous-même que vous aimez votre nouvelle réponse? C'est juste 'meh'. – sjas

+0

Non. Je répondais à un autre commentaire (maintenant supprimé, apparemment), qui m'a recommandé de remplacer '> tmp $$ && source ./tmp$$' par '' | bash'. Je suppose qu'il a décidé de supprimer son commentaire depuis que j'ai édité ma réponse par sa suggestion. – Jack