Comment diviser une chaîne en shell et obtenir le dernier champ

Supposons que j’ai la chaîne 1:2:3:4:5 et que je veuille obtenir son dernier champ ( 5 dans ce cas). Comment puis-je le faire en utilisant Bash? J’ai essayé de cut , mais je ne sais pas comment spécifier le dernier champ avec -f .

Vous pouvez utiliser des opérateurs de chaîne :

 $ foo=1:2:3:4:5 $ echo ${foo##*:} 5 

Cela coupe tout du front jusqu’à un «:», avidement.

 ${foo <-- from variable foo ## <-- greedy front trim * <-- matches anything : <-- until the last ':' } 

Une autre façon consiste à inverser avant et après la cut :

 $ echo ab:cd:ef | rev | cut -d: -f1 | rev ef 

Cela rend très facile d’obtenir le dernier mais un seul champ, ou toute gamme de champs numérotés à partir de la fin.

Il est difficile d’obtenir le dernier champ en utilisant cut, mais voici (un ensemble de) des solutions dans awk et perl

 $ echo 1: 2: 3: 4: 5 |  awk -F: '{print $ NF}'
 5
 $ echo 1: 2: 3: 4: 5 |  perl -F: -wane 'print $ F [-1]'
 5

En supposant un usage assez simple (pas d’échappatoire du délimiteur, par exemple), vous pouvez utiliser grep:

 $ echo "1:2:3:4:5" | grep -oE "[^:]+$" 5 

Ventilation – trouvez tous les caractères non le délimiteur ([^:]) à la fin de la ligne ($). -o imprime uniquement la partie correspondante.

Une manière:

 var1="1:2:3:4:5" var2=${var1##*:} 

Un autre, utilisant un tableau:

 var1="1:2:3:4:5" saveIFS=$IFS IFS=":" var2=($var1) IFS=$saveIFS var2=${var2[@]: -1} 

Encore un autre avec un tableau:

 var1="1:2:3:4:5" saveIFS=$IFS IFS=":" var2=($var1) IFS=$saveIFS count=${#var2[@]} var2=${var2[$count-1]} 

En utilisant des expressions rationnelles Bash (version> = 3.2):

 var1="1:2:3:4:5" [[ $var1 =~ :([^:]*)$ ]] var2=${BASH_REMATCH[1]} 

Utiliser sed :

 $ echo '1:2:3:4:5' | sed 's/.*://' # => 5 $ echo '' | sed 's/.*://' # => (empty) $ echo ':' | sed 's/.*://' # => (empty) $ echo ':b' | sed 's/.*://' # => b $ echo '::c' | sed 's/.*://' # => c $ echo 'a' | sed 's/.*://' # => a $ echo 'a:' | sed 's/.*://' # => (empty) $ echo 'a:b' | sed 's/.*://' # => b $ echo 'a::c' | sed 's/.*://' # => c 
 $ echo "abcde" | tr ' ' '\n' | tail -1 e 

Traduisez simplement le délimiteur dans une nouvelle ligne et choisissez la dernière entrée avec la tail -1 .

Si votre dernier champ est un seul caractère, vous pouvez le faire:

 a="1:2:3:4:5" echo ${a: -1} echo ${a:(-1)} 

Vérifiez la manipulation des chaînes dans bash .

Utiliser Bash.

 $ var1="1:2:3:4:0" $ IFS=":" $ set -- $var1 $ eval echo \$${#} 0 
 echo "a:b:c:d:e"|xargs -d : -n1|tail -1 

Tout d’abord, xargs le divise en utilisant “:”, – n1 signifie que chaque ligne n’a qu’une seule partie.

Il y a beaucoup de bonnes réponses ici, mais je veux quand même partager celle-ci en utilisant le nom de base :

  basename $(echo "a:b:c:d:e" | tr ':' '/') 

Cependant, cela échouera s’il y a déjà des ‘/’ dans votre chaîne . Si slash / est votre délimiteur, alors vous devez simplement utiliser le nom de base.

Ce n’est pas la meilleure réponse mais cela montre simplement comment vous pouvez être créatif en utilisant les commandes bash.

 for x in `echo $str | tr ";" "\n"`; do echo $x; done 

Pour ceux qui sont à l’aise avec Python, https://github.com/Russell91/pythonpy est un bon choix pour résoudre ce problème.

 $ echo "a:b:c:d:e" | py -x 'x.split(":")[-1]' 

De l’aide de pythonpy: -x treat each row of stdin as x .

Avec cet outil, il est facile d’écrire du code python qui est appliqué à l’entrée.

une solution utilisant le readin intégré

 IFS=':' read -a field <<< "1:2:3:4:5" echo ${field[4]}