web-dev-qa-db-fra.com

Utiliser Awk pour extraire une sous-chaîne

Étant donné un nom d'hôte au format aaa0.bbb.ccc, Je veux extraire la première sous-chaîne avant ., C'est, aaa0 dans ce cas. J'utilise le script awk suivant pour le faire,

echo aaa0.bbb.ccc | awk '{if (match($0, /\./)) {print substr($0, 0, RSTART - 1)}}'

Tandis que le script exécuté sur une machine, A produit aaa0, en cours d'exécution sur la machine B ne produit que aaa, sans 0 à la fin. Les deux machines fonctionnent Ubuntu/Linaro, mais A exécute une version plus récente de awk (gawk avec la version 3.1.8 alors que B avec un ancien awk (mawk avec la version 1.2)

Je demande en général, comment écrire un script awk compatible qui exécute la même fonctionnalité ...

29
Richard

Vous voulez juste définir le séparateur de champs comme . en utilisant le -F option et imprimer le premier champ:

$ echo aaa0.bbb.ccc | awk -F'.' '{print $1}'
aaa0

Même chose mais en utilisant cut:

$ echo aaa0.bbb.ccc | cut -d'.' -f1
aaa0

Ou avec sed:

$ echo aaa0.bbb.ccc | sed 's/[.].*//'
aaa0

Même grep:

$ echo aaa0.bbb.ccc | grep -o '^[^.]*'
aaa0
56
Chris Seymour

Je demande en général, comment écrire un script awk compatible qui exécute la même fonctionnalité ...

Résoudre le problème dans votre question est facile. (vérifiez la réponse des autres).

Si vous voulez écrire un script awk qui soit portable pour toutes les implémentations et versions de awk (gawk/nawk/mawk ...), c'est vraiment difficile, même avec --posix (gawk)

par exemple:

  • certains awk fonctionnent sur des chaînes en termes de caractères, d'autres avec des octets
  • certains supporte l'évasion \x, d'autres non
  • FS l'interprète fonctionne différemment
  • mots-clés/mots réservés abréviation restriction
  • certaines restrictions d'opérateur, par exemple. **
  • même même awk impl. (gawk par exemple), les versions 4.0 et 3.x ont aussi une différence.
  • la mise en œuvre de certaines fonctions sont également différentes. (votre problème est un exemple, voir ci-dessous)

bien tous les points ci-dessus sont juste parlé en général. De retour à votre problème, votre problème est uniquement lié à la fonctionnalité fondamentale de awk. awk '{print $x}' La ligne comme ça fonctionnera tous les awks.

Il y a deux raisons pour lesquelles votre ligne awk se comporte différemment sur gawk et mawk:

  • votre fonction substr() utilisée à tort. c'est la cause principale. vous avez substr($0, 0, RSTART - 1) le 0 devrait être 1, quel que soit votre awk. Le tableau awk, la chaîne idx, etc. sont basés sur 1.

  • gawk et mawk ont ​​implémenté substr() différemment.

5
Kent

Ou utilisez simplement couper:

echo aaa0.bbb.ccc | cut -d'.' -f1
4
perreal

Vous n'avez besoin d'aucune commande externe, utilisez simplement Parameter Expansion dans bash:

hostname=aaa0.bbb.ccc
echo ${hostname%%.*}
2
choroba

Vous n'avez pas besoin de awk pour ça ...

echo aaa0.bbb.ccc | cut -d. -f1
cut -d. -f1 <<< aaa0.bbb.ccc

echo aaa0.bbb.ccc | { IFS=. read a _ ; echo $a ; }
{ IFS=. read a _ ; echo $a ; } <<< aaa0.bbb.ccc 

x=aaa0.bbb.ccc; echo ${x/.*/}

Options plus lourdes:

sed:
echo aaa0.bbb.ccc | sed 's/\..*//'
sed 's/\..*//' <<< aaa0.bbb.ccc 
awk:
echo aaa0.bbb.ccc | awk -F. '{print $1}'
awk -F. '{print $1}' <<< aaa0.bbb.ccc 
2
anishsane