331 votes

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 veux obtenir son dernier champ (5 dans ce cas). Comment puis-je faire cela en utilisant Bash? J'ai essayé cut, mais je ne sais pas comment spécifier le dernier champ avec -f.

492voto

Stephen Points 16714

Vous pouvez utiliser opérateurs de chaîne:

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

Cela supprime tout depuis le début jusqu'à ':', de manière gourmande.

${foo  <-- de la variable foo
  ##   <-- suppression du début de manière gourmande
  *    <-- correspond à n'importe quoi
  :    <-- jusqu'au dernier ':'
 }

7 votes

Alors que cela fonctionne pour le problème donné, la réponse de William ci-dessous (stackoverflow.com/a/3163857/520162) renvoie également 5 si la chaîne est 1:2:3:4:5: (alors que l'utilisation des opérateurs de chaîne renvoie un résultat vide). Ceci est particulièrement pratique lors de l'analyse des chemins qui pourraient contenir (ou non) un caractère de fin /.

10 votes

Comment feriez-vous alors le contraire de ceci? pour afficher '1:2:3:4:'?

16 votes

Et comment garde-t-on la partie avant le dernier séparateur ? Apparemment en utilisant ${foo%:*}. # - du début; % - de la fin. #, % - correspondance la plus courte; ##, %% - correspondance la plus longue.

374voto

a3nm Points 2733

Une autre façon est d'inverser avant et après cut :

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

Cela rend très facile d'obtenir le dernier champ, ou n'importe quelle plage de champs numérotés depuis la fin.

19 votes

Cette réponse est agréable car elle utilise 'couper', avec lequel l'auteur est (probablement) déjà familier. De plus, j'aime cette réponse car je utilise 'couper' et j'avais exactement cette question, d'où la découverte de cette discussion via une recherche.

6 votes

Voici de quoi copier-coller pour les personnes utilisant des espaces comme délimiteurs : echo "1 2 3 4" | rev | cut -d " " -f1 | rev

2 votes

Le rev | cut -d -f1 | rev est tellement intelligent! Merci! m'a beaucoup aidé (mon cas d'utilisation était rev | -d ' ' -f 2- | rev

89voto

William Pursell Points 56211

Il est difficile d'obtenir le dernier champ en utilisant cut, mais voici quelques solutions en awk et perl

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

6 votes

Grand avantage de cette solution par rapport à la réponse acceptée: elle correspond également aux chemins qui contiennent ou ne contiennent pas un caractère de fin /: /a/b/c/d et /a/b/c/d/ donnent le même résultat (d) lors du traitement de pwd | awk -F/ '{print $NF}'. La réponse acceptée donne un résultat vide dans le cas de /a/b/c/d/

0 votes

@eckes Dans le cas d'une solution AWK, sur GNU bash, version 4.3.48(1)-release, ce n'est pas vrai, car cela dépend si vous avez ou non une barre oblique finale.Simplement, AWK utilisera / comme délimiteur, et si votre chemin est /my/path/dir/, il utilisera la valeur après le dernier délimiteur, qui est simplement une chaîne vide. Il est donc préférable d'éviter la barre oblique finale si vous avez besoin de faire une telle chose comme je le fais.

0 votes

Comment pourrais-je obtenir la sous-chaîne JUSQU'AU dernier champ?

35voto

En supposant une utilisation assez simple (pas d'échappement du délimiteur, par exemple), vous pouvez utiliser grep:

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

Détails - trouver tous les caractères qui ne sont pas le délimiteur ([^:]) à la fin de la ligne ($). -o n'imprime que la partie correspondante.

1 votes

-E signifie l'utilisation de la syntaxe étendue ; [^...] signifie tout sauf le(s) caractère(s) répertorié(s) ; + une ou plusieurs occurrences de ce type (prendra la longueur maximale possible pour le modèle ; cet élément est une extension de gnu) - pour l'exemple, les caractères de séparation sont les deux points.

19voto

Dennis Williamson Points 105818

Une façon :

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

Une autre, en utilisant un tableau :

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

Encore une autre avec un tableau :

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

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

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X