193 votes

Extraire une partie d'une chaîne en utilisant bash/cut/split

Je ai une chaîne comme celui-ci:

/var/cpanel/users/joebloggs:DNS9=domain.example

Je besoin d'extraire le nom d'utilisateur (joebloggs) de cette chaîne et de le stocker dans une variable.

Le format de la chaîne sera toujours la même à l'exception de joebloggs et domain.example donc je pense que la chaîne peut être divisée en deux en utilisant cut?

La première division diviserait par : et nous stockerions la première partie dans une variable à passer à la seconde fonction de division.

La deuxième division diviserait par / et stockerait le dernier mot (joebloggs) dans une variable

Je sais comment faire cela en PHP en utilisant des tableaux et des divisions mais je suis un peu perdu en bash.

490voto

beroe Points 3365

Pour extraire joebloggs de cette chaîne en bash en utilisant l'expansion des paramètres sans processus supplémentaire...

MYVAR="/var/cpanel/users/joebloggs:DNS9=domain.example"

NAME=${MYVAR%:*}  # conserver la partie avant le deux-points
NAME=${NAME##*/}  # conserver la partie après le dernier slash
echo $NAME

Ne dépend pas de joebloggs étant à une profondeur particulière dans le chemin.


Résumé

Un aperçu de quelques modes d'expansion de paramètres, pour référence...

${MYVAR#modèle}     # supprimer la correspondance la plus courte du modèle depuis le début
${MYVAR##modèle}    # supprimer la correspondance la plus longue du modèle depuis le début
${MYVAR%modèle}     # supprimer la correspondance la plus courte du modèle depuis la fin
${MYVAR%%modèle}    # supprimer la correspondance la plus longue du modèle depuis la fin

Donc # signifie correspondance depuis le début (pensez à une ligne de commentaire) et % signifie depuis la fin. Une instance signifie la plus courte et deux instances signifie la plus longue.

Vous pouvez obtenir des sous-chaînes en fonction de la position en utilisant des chiffres :

${MYVAR:3}   # Supprimer les trois premiers caractères (laissant 4..fin)
${MYVAR::3}  # Renvoyer les trois premiers caractères
${MYVAR:3:5} # Les cinq caractères suivants après avoir supprimé les trois premiers (caractères 4-9)

Vous pouvez également remplacer des chaînes ou modèles particuliers en utilisant :

${MYVAR/recherche/remplacement}

Le modèle est dans le même format que la correspondance de noms de fichier, donc * (n'importe quels caractères) est commun, suivi souvent d'un symbole particulier comme / ou .

Exemples :

Étant donné une variable comme

MYVAR="users/joebloggs/domain.example"

Supprimer le chemin laissant le nom de fichier (tous les caractères jusqu'à un slash) :

echo ${MYVAR##*/}
domain.example

Supprimer le nom de fichier, laissant le chemin (supprimer la correspondance la plus courte après le dernier /) :

echo ${MYVAR%/*}
users/joebloggs

Obtenir juste l'extension du fichier (supprimer tout avant le dernier point) :

echo ${MYVAR##*.}
example

REMARQUE : Pour effectuer deux opérations, vous ne pouvez pas les combiner, mais devez les assigner à une variable intermédiaire. Donc pour obtenir le nom de fichier sans chemin ni extension :

NAME=${MYVAR##*/}      # supprimer la partie avant le dernier slash
echo ${NAME%.*}        # depuis la nouvelle variable, retirer la partie après le dernier point
domain

65voto

Stefano Sanfilippo Points 11123

Définissez une fonction comme ceci :

getUserName() {
    echo $1 | cut -d : -f 1 | xargs basename
}

Et passez la chaîne en tant que paramètre :

userName=$(getUserName "/var/cpanel/users/joebloggs:DNS9=domain.example")
echo $userName

28voto

David W. Points 49436

Que dire de sed? Cela fonctionnera en une seule commande:

sed 's#.*/\([^:]*\).*#\1#' <<<$string
  • Les # sont utilisés comme diviseurs regex au lieu de / car la chaîne contient un /.
  • .*/ capture la chaîne jusqu'au dernier backslash.
  • \( .. \) marque un groupe de capture. C'est \([^:]*\).
    • Le [^:] signifie n'importe quel caractère _sauf deux points, et le * signifie zéro ou plus.
  • .* signifie le reste de la ligne.
  • \1 signifie substituer ce qui a été trouvé dans le premier (et unique) groupe de capture. C'est le nom.

Voici la correspondance de la chaîne avec l'expression régulière:

        /var/cpanel/users/           joebloggs  :DNS9=domain.example joebloggs
sed 's#.*/                          \([^:]*\)   .*              #\1       #'

18voto

janos Points 22603

Utiliser un seul Awk :

... | awk -F '[/:]' '{print $5}'

C'est-à-dire, en utilisant comme séparateur de champ soit / soit :, le nom d'utilisateur est toujours dans le champ 5.

Pour le stocker dans une variable :

username=$(... | awk -F '[/:]' '{print $5}')

Une implémentation plus flexible avec sed qui ne nécessite pas que le nom d'utilisateur soit dans le champ 5 :

... | sed -e s/:.*// -e s?.*/??

C'est-à-dire, supprimer tout de : et au-delà, puis supprimer tout jusqu'au dernier /. sed est probablement plus rapide que awk, donc cette alternative est définitivement meilleure.

12voto

Yann Moisan Points 1584

Utilisation d'un seul sed

echo "/var/cpanel/users/joebloggs:DNS9=domain.example" | sed 's/.*\/\(.*\):.*/\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