web-dev-qa-db-fra.com

Comment créer des numéronymes en bash

J'essaie d'écrire un code qui transformerait n'importe quel mot donné en son nom.

par exemple: internationalisation = i18n (premier caractère + nombre de caractères entre + dernier caractère)

J'ai trouvé comment trouver le premier et le dernier caractère et je sais comment trouver la partie numérique, mais je ne sais pas comment mettre le nombre entre le premier et le dernier caractère.

Le code que j'ai utilisé pour obtenir la partie numérique est:

cut -c 2- | rev | cut -c 2- | rev | tr -d [:space:]| wc -c 

Le code que j'ai utilisé pour obtenir le premier et le dernier chacarters:

awk -F "" '{print $1,$NF}'
10
arthionne

Une autre solution awk:

awk '{l=length($1); print substr($1,1,1) l-2 substr($1,l,1)}'
  • l=length($1) - Définissez la variable l sur la longueur de votre chaîne (en supposant que la chaîne d'entrée se trouve dans la première colonne et ne contient pas d'espaces)
  • substr($1,1,1) - (colonne #, point de départ, point de fin) donc imprimez la colonne 1, en commençant à la position 1, et imprimez 1 caractère.
  • l-2 - Longueur de la chaîne moins 2
  • substr($1,l,1) - Imprime la colonne 1 à partir de la position l (longueur de chaîne) et imprime 1 caractère.
10
jesse_b

Bien que je trouve l'utilisation de awk avec un séparateur de champs vide quelque peu "innovante", la solution la plus simple à mon avis n'est qu'une petite extension de la vôtre:

awk -F "" '{print $1 (NF-2) $NF}'

Cela ne fonctionne bien sûr qu'avec des mots de trois lettres ou plus. Pour gérer le cas général:

awk -F "" '{if (NF>2) print $1 (NF-2) $NF; else print $0}'

Comme explication:

  • En définissant le séparateur de champ sur "vide" avec -F "", l'entrée est divisée en champs après chaque caractère, c'est-à-dire que chaque caractère de l'entrée est considéré comme un "champ" individuel accessible via $n in awk expressions (avec n étant le numéro de champ allant de 1 à NF). Btw, le GNU Awk User's Guide --- fournit de tels cas d'utilisation comme exemples , donc je me tiens corrigé sur mes préoccupations précédentes concernant l'utilisation d'un FS vide. , notez que le manuel dit "Ceci est une extension courante; elle n'est pas spécifiée par la norme POSIX".
  • if le nombre de champs (c'est-à-dire les caractères, ici) est supérieur à deux, imprimez le premier champ/caractère ($1), l'expression évaluée (NF-2) qui correspond au nombre de caractères compris entre le premier et le dernier, et le dernier champ/caractère ($NF). Notez que l'appel print tel qu'utilisé ici ne produit pas d'espace entre les jetons de sortie individuels; cela se produit uniquement lorsque vous séparez les arguments par des virgules au lieu de l'espace (voir par exemplele GNU Awk User's Guide ).
  • else affiche simplement l'expression d'entrée entière, accessible via $0

Notez que si nous pouvions alimenter une entrée à deux caractères, par exempleat, dans le premier exemple de code, nous obtiendrions une sortie indésirable (mais formellement correcte) comme a0t (car il n'y a, dans ce cas, aucun caractère entre le premier et le dernier).

Notez également , et cela est important, que si vous fournissez une chaîne contenant des espaces de début ou de fin à cet appel awk, comme dans echo " hello" | awk <etc.>, alors cet espace de tête/de fin serait traité comme le premier/dernier caractère, donnant ainsi un comportement indésirable!

17
AdminBee

Dans ksh93, bash ou zsh:

numeronym() {
  (( ${#1} > 2 )) || return
  printf '%s%d%s\n' "${1:0:1}" "$(( ${#1} - 2 ))" "${1: -1:1}"
}

Cela fonctionne sur le premier (uniquement) paramètre en imprimant la première lettre (nombre de caractères moins 2) et la dernière lettre.

15
Jeff Schaller

Portable à de nombreuses coquilles:

a=internationalization;
if [ "${#a}" -gt 2 ]; then 
    a="${a%"${a#?}"}$((${#a}-2))${a#"${a%?}"}";
fi
printf '%s\n' "${a}"

En tant que fonction (légèrement moins portable):

numeronym() {  a="$1";
               if [ "${#1}" -gt 2 ]; then 
                    a="${a%"${a#?}"}$((${#a}-2))${a#"${a%?}"}";
               fi;
               printf '%s\n' "${a}";
            }

Appelez-le comme:

$ numeronym internationalization
i18n

S'il doit être awk:

$ echo internationalization |
      awk '{ print (NF>2) ? $1 NF-2 $NF : $0 }' FS=''

i18n
5
Isaac