Question Extraire la sous-chaîne dans Bash


Étant donné un nom de fichier sous la forme someletters_12345_moreleters.ext, Je veux extraire les 5 chiffres et les mettre dans une variable.

Donc, pour souligner le point, j'ai un nom de fichier avec x nombre de caractères, puis une séquence à cinq chiffres entourée d'un trait de soulignement unique de chaque côté, puis un autre ensemble de x nombre de caractères. Je veux prendre le nombre à 5 chiffres et le mettre dans une variable.

Je suis très intéressé par le nombre de manières différentes que cela peut être accompli.


499
2018-01-09 13:53


origine


Réponses:


Utilisation Couper:

echo 'someletters_12345_moreleters.ext' | cut -d'_' -f 2

Plus générique:

INPUT='someletters_12345_moreleters.ext'
SUBSTRING=$(echo $INPUT| cut -d'_' -f 2)
echo $SUBSTRING

503
2018-01-09 13:56



Si X est constante, l'extension de paramètre suivante effectue l'extraction de la sous-chaîne:

b=${a:12:5}

12 est le décalage (base zéro) et 5 est la longueur

Si les traits de soulignement autour des chiffres sont les seuls dans l'entrée, vous pouvez supprimer le préfixe et le suffixe (respectivement) en deux étapes:

tmp=${a#*_}   # remove prefix ending in "_"
b=${tmp%_*}   # remove suffix starting with "_"

S'il y a d'autres underscores, c'est probablement faisable de toute façon, quoique plus difficile. Si quelqu'un sait comment effectuer les deux expansions dans une seule expression, j'aimerais aussi le savoir.

Les deux solutions présentées sont purement bash, sans processus de ponte impliqué, donc très rapide.


756
2018-01-09 15:52



Solution générique où le numéro peut être n'importe où dans le nom de fichier, en utilisant la première de ces séquences:

number=$(echo $filename | egrep -o '[[:digit:]]{5}' | head -n1)

Une autre solution pour extraire exactement une partie d'une variable:

number=${filename:offset:length}

Si votre nom de fichier a toujours le format stuff_digits_... vous pouvez utiliser awk:

number=$(echo $filename | awk -F _ '{ print $2 }')

Encore une autre solution pour supprimer tout sauf les chiffres, utilisez

number=$(echo $filename | tr -cd '[[:digit:]]')

74
2018-01-09 14:00



essayez d'utiliser cut -c startIndx-stopIndx


59
2017-09-22 17:54



Dans le cas où quelqu'un veut des informations plus rigoureuses, vous pouvez également le rechercher dans l'homme bash comme ceci

$ man bash [press return key]
/substring  [press return key]
[press "n" key]
[press "n" key]
[press "n" key]
[press "n" key]

Résultat:

$ {paramètre: offset}
       $ {parameter: offset: longueur}
              Extension de sous-chaîne. S'étend jusqu'à des caractères de longueur
              paramètre commençant au caractère spécifié par offset. Si
              length est omis, se développe en sous-chaîne de paramètre start-
              au niveau du caractère spécifié par offset. longueur et décalage sont
              expressions arithmétiques (voir ÉVALUATION ARITHMÉTIQUE ci-dessous). Si
              offset est évalué à un nombre inférieur à zéro, la valeur est utilisée
              en décalage par rapport à la fin de la valeur du paramètre. Arithmétique
              les expressions commençant par - doivent être séparées par des espaces
              du précédent: à distinguer de l'utilisation par défaut
              L'expansion des valeurs. Si la longueur est évaluée à un nombre inférieur à
              zéro, et le paramètre n'est pas @ et n'est pas indexé ou associatif
              tableau, il est interprété comme un décalage par rapport à la fin de la valeur
              paramètre plutôt qu’un nombre de caractères, et
              sion sont les caractères entre les deux décalages. Si le paramètre est
              @, le résultat est la longueur des paramètres de position commençant à off
              ensemble. Si paramètre est un nom de tableau indexé indiqué par @ ou
              *, le résultat est la longueur des membres du tableau commençant par
              $ {paramètre [offset]}. Un décalage négatif est pris par rapport à
              un plus grand que l'index maximum du tableau spécifié. Sous-
              extension de chaîne appliquée à un tableau associatif produit unde-
              des résultats finis. Notez qu'un décalage négatif doit être séparé
              du côlon par au moins un espace pour éviter d'être confus
              avec le: - expansion. L'indexation de sous-chaîne est basée sur zéro sauf si
              les paramètres de position sont utilisés, auquel cas l'indexation
              commence à 1 par défaut. Si le décalage est 0 et la position
              les paramètres sont utilisés, $ 0 est préfixé à la liste.

29
2018-05-31 15:00



Construire sur la réponse de jor (ce qui ne marche pas pour moi):

substring=$(expr "$filename" : '.*_\([^_]*\)_.*')

17
2018-01-09 15:41



Je suis surpris que cette pure solution de bash ne soit pas apparue:

a="someletters_12345_moreleters.ext"
IFS="_"
set $a
echo $2
# prints 12345

Vous voulez probablement réinitialiser IFS à quelle valeur il était avant, ou unset IFS ensuite!


15
2018-06-03 17:34



Suivant les exigences

J'ai un nom de fichier avec x nombre de caractères puis un cinq chiffres   séquence entourée d'un seul trait de soulignement de chaque côté puis un autre   ensemble de x nombre de caractères. Je veux prendre le numéro à 5 chiffres et   mettre cela dans une variable.

J'ai trouvé quelques grep des moyens qui peuvent être utiles:

$ echo "someletters_12345_moreleters.ext" | grep -Eo "[[:digit:]]+" 
12345

ou mieux

$ echo "someletters_12345_moreleters.ext" | grep -Eo "[[:digit:]]{5}" 
12345

Et puis avec -Po syntaxe:

$ echo "someletters_12345_moreleters.ext" | grep -Po '(?<=_)\d+' 
12345

Ou si vous voulez le faire correspondre exactement à 5 caractères:

$ echo "someletters_12345_moreleters.ext" | grep -Po '(?<=_)\d{5}' 
12345

Enfin, pour qu'il soit stocké dans une variable, il suffit d'utiliser le var=$(command) syntaxe.


11
2018-06-26 12:13



Sans aucun sous-processus, vous pouvez:

shopt -s extglob
front=${input%%_+([a-zA-Z]).*}
digits=${front##+([a-zA-Z])_}

Une très petite variante de ceci fonctionnera aussi dans ksh93.


9
2018-01-09 16:13



Si nous nous concentrons sur le concept de:
    "Une série de (un ou plusieurs) chiffres"

Nous pourrions utiliser plusieurs outils externes pour extraire les nombres.
Nous pourrions facilement effacer tous les autres caractères, soit sed, soit tr:

name='someletters_12345_moreleters.ext'

echo $name | sed 's/[^0-9]*//g'    # 12345
echo $name | tr -c -d 0-9          # 12345

Mais si $ name contient plusieurs séries de nombres, ce qui précède échouera:

Si "name = someletters_12345_moreleters_323_end.ext", alors:

echo $name | sed 's/[^0-9]*//g'    # 12345323
echo $name | tr -c -d 0-9          # 12345323

Nous devons utiliser des expressions régulières (regex).
Pour ne sélectionner que la première exécution (12345 non 323) dans sed et perl:

echo $name | sed 's/[^0-9]*\([0-9]\{1,\}\).*$/\1/'
perl -e 'my $name='$name';my ($num)=$name=~/(\d+)/;print "$num\n";'

Mais on pourrait aussi bien le faire directement dans bash(1) :

regex=[^0-9]*([0-9]{1,}).*$; \
[[ $name =~ $regex ]] && echo ${BASH_REMATCH[1]}

Cela nous permet d'extraire la première série de chiffres de n'importe quelle longueur
entouré par d'autres textes / caractères.

Remarque: regex=[^0-9]*([0-9]{5,5}).*$; ne correspondra exactement qu'à 5 chiffres. :-)

(1): plus rapide que d'appeler un outil externe pour chaque texte court. Pas plus rapide que de faire tout le traitement à l'intérieur de sed ou awk pour les gros fichiers.


9
2017-08-05 08:11



Voici une solution de préfixe-suffixe (similaire aux solutions proposées par JB et Darron) qui correspond au premier bloc de chiffres et ne dépend pas des traits de soulignement environnants:

str='someletters_12345_morele34ters.ext'
s1="${str#"${str%%[[:digit:]]*}"}"   # strip off non-digit prefix from str
s2="${s1%%[^[:digit:]]*}"            # strip off non-digit suffix from s1
echo "$s2"                           # 12345

8
2018-05-06 12:50