web-dev-qa-db-fra.com

Comment diviser une chaîne dans Shell et obtenir le dernier champ

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

240
cd1

Vous pouvez utiliser opérateurs de chaîne :

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

Cela coupe tout de l'avant jusqu'à un ':', goulûment.

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

Une autre méthode consiste à inverser avant et après cut:

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

Il est donc très facile d’obtenir l’avant dernier champ ou toute plage de champs numérotés à partir de la fin.

314
a3nm

Il est difficile d'obtenir le dernier champ en utilisant cut, mais voici (un ensemble de) 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 
65
William Pursell

Dans l’hypothèse d’une utilisation assez simple (par exemple, pas d’échappement du délimiteur), vous pouvez utiliser grep:

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

Ventilation - trouvez tous les caractères, pas le délimiteur ([^:]) à la fin de la ligne ($). -o n'imprime que la partie correspondante.

25

Une manière:

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

Un autre, en 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]}

Utilisation d'expressions régulières Bash (version> = 3.2):

var1="1:2:3:4:5"
[[ $var1 =~ :([^:]*)$ ]]
var2=${BASH_REMATCH[1]}
18
Dennis Williamson
$ echo "a b c d e" | tr ' ' '\n' | tail -1
e

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

8
user3133260

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
6
Rafael

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

a="1:2:3:4:5"

echo ${a: -1}
echo ${a:(-1)}

Vérifiez manipulation de chaîne dans bash .

4
Ab Irato

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

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

Cependant, il échouera s'il y a déjà des "/" dans votre chaîne. Si slash/est votre délimiteur, vous devez (et devriez) 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.

3
021

Utilisation de Bash.

$ var1="1:2:3:4:0"
$ IFS=":"
$ set -- $var1
$ eval echo  \$${#}
0
2
ghostdog74

Si vous aimez python et avez la possibilité d'installer un paquet, vous pouvez utiliser cet utilitaire python .

# install pythonp
pythonp -m pip install pythonp

echo "1:2:3:4:5" | pythonp "l.split(':')[-1]"
5
2
bombs
echo "a:b:c:d:e"|xargs -d : -n1|tail -1

Première utilisation, xargs le divise en utilisant ":", - n1 signifie que chaque ligne ne comporte qu'une partie. Ensuite, extrayez la dernière partie.

2
Crytis

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]'

Dans 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.

1
Christoph Böddeker
for x in `echo $str | tr ";" "\n"`; do echo $x; done
1
Nahid Akbar

une solution utilisant la lecture intégrée

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

La correspondance des regex dans sed est gourmande (va toujours à la dernière occurrence), que vous pouvez utiliser à votre avantage ici:

$ foo=1:2:3:4:5
$ echo ${foo} | sed "s/.*://"
5
0
slushy

La réponse pourrait être un peu tardive, bien qu'une solution simple consiste à inverser l'ordre de la chaîne d'entrée. Cela vous permettrait de toujours gagner le dernier élément, quelle que soit sa longueur. 

[chris@desktop bin]$ echo 1:2:3:4:5 | rev | cut -d: -f1
5

Il est important de noter cependant que si vous utilisez cette méthode et que les nombres sont supérieurs à un chiffre (ou supérieurs à un caractère dans toutes les circonstances), vous devrez exécuter une autre commande "rev" sur la sortie redirigée.

[chris@desktop bin]$ echo 1:2:3:4:5:8:24 | rev | cut -d: -f1
42
[chris@desktop bin]$ echo 1:2:3:4:5:8:24 | rev | cut -d: -f1 | rev
24

J'espère pouvoir aider, acclamations

0
Chris