web-dev-qa-db-fra.com

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

J'ai une chaîne comme celle-ci:

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

J'ai 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 le même à l'exception de joebloggs et domain.com donc je pense que la chaîne peut être divisée deux fois à l'aide de cut?

La première division serait scindée par : et nous stockerions la première partie dans une variable à transmettre à la deuxième fonction de scission.

La seconde scission serait scindée par / et stockerait le dernier mot (joebloggs) dans une variable

Je sais comment faire cela en php en utilisant des tableaux et des scissions, mais je suis un peu perdu en bash.

92
Craig Edmonds

Pour extraire joebloggs de cette chaîne dans bash en utilisant l’extension de paramètre sans aucun processus supplémentaire ...

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

NAME=${MYVAR%:*}  # retain the part before the colon
NAME=${NAME##*/}  # retain the part after the last slash
echo $NAME

Ne dépend pas de joebloggs être à une profondeur particulière du chemin.


Résumé

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

${MYVAR#pattern}     # delete shortest match of pattern from the beginning
${MYVAR##pattern}    # delete longest match of pattern from the beginning
${MYVAR%pattern}     # delete shortest match of pattern from the end
${MYVAR%%pattern}    # delete longest match of pattern from the end

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

Vous pouvez obtenir des sous-chaînes basées sur la position en utilisant des nombres:

${MYVAR:3}   # Remove the first three chars (leaving 4..end)
${MYVAR::3}  # Return the first three characters
${MYVAR:3:5} # The next five characters after removing the first 3 (chars 4-9)

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

${MYVAR/search/replace}

Le pattern est dans le même format que la correspondance de nom de fichier, donc * (tous les caractères) est commun, souvent suivi d'un symbole particulier comme / ou .

Exemples:

Étant donné une variable comme

MYVAR="users/joebloggs/domain.com" 

Supprimez le chemin en laissant le nom de fichier (tous les caractères jusqu'à la barre oblique):

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

Supprimez le nom du fichier en laissant le chemin (supprimez la correspondance la plus courte après le dernier /):

echo ${MYVAR%/*}
users/joebloggs

Obtenir uniquement l'extension de fichier (tout supprimer avant la dernière période):

echo ${MYVAR##*.}
com

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

NAME=${MYVAR##*/}      # remove part before last slash
echo ${NAME%.*}        # from the new var remove the part after the last period
domain
261
beroe

Définissez une fonction comme celle-ci:

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.com")
echo $userName
35
Stefano Sanfilippo

Qu'en est-il de Sed? Cela fonctionnera en une seule commande:

sed 's#.*/\([^:]*\).*#\1#' <<<$string
  • Les # sont utilisés pour les diviseurs de regex au lieu de / car la chaîne contient /.
  • .*/ saisit la chaîne jusqu'à la dernière barre oblique inverse.
  • \( .. \) marque un groupe de capture. C'est \([^:]*\).
    • Le [^:] dit n'importe quel caractère _ sauf un deux-points, et le * signifie zéro ou plus.
  • .* signifie le reste de la ligne.
  • \1 signifie remplacer par ce qui a été trouvé dans le premier (et le seul) groupe de capture. C'est le nom.

Voici la ventilation correspondant à la chaîne avec l'expression régulière:

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

Utiliser un seul sed

echo "/var/cpanel/users/joebloggs:DNS9=domain.com" | sed 's/.*\/\(.*\):.*/\1/'
10
Yann Moisan

En utilisant un seul Awk:

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

C'est-à-dire qu'en utilisant comme séparateur de champ soit / ou :, 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 n'exige pas que le nom d'utilisateur soit dans le champ 5:

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

En d’autres termes, supprimez tout ce qui se trouve dans : et au-delà, puis supprimez tout jusqu’au dernier /. sed est probablement aussi plus rapide que awk, donc cette alternative est définitivement meilleure.

9
janos