J'ai une chaîne:
one_two_three_four_five
J'ai besoin de sauvegarder dans une variable A
valeur two
et dans la variable B
valeur four
de la chaîne ci-dessus
Utilisez cut
avec _
comme délimiteur de champ et obtenez les champs souhaités:
A="$(cut -d'_' -f2 <<<'one_two_three_four_five')"
B="$(cut -d'_' -f4 <<<'one_two_three_four_five')"
Vous pouvez également utiliser echo
et pipe au lieu de la chaîne Here:
A="$(echo 'one_two_three_four_five' | cut -d'_' -f2)"
B="$(echo 'one_two_three_four_five' | cut -d'_' -f4)"
Exemple:
$ s='one_two_three_four_five'
$ A="$(cut -d'_' -f2 <<<"$s")"
$ echo "$A"
two
$ B="$(cut -d'_' -f4 <<<"$s")"
$ echo "$B"
four
En utilisant uniquement des constructions sh POSIX, vous pouvez utiliser constructions de substitution de paramètres pour analyser un délimiteur à la fois. Notez que ce code suppose qu'il existe le nombre requis de champs, sinon le dernier champ est répété.
string='one_two_three_four_five'
remainder="$string"
first="${remainder%%_*}"; remainder="${remainder#*_}"
second="${remainder%%_*}"; remainder="${remainder#*_}"
third="${remainder%%_*}"; remainder="${remainder#*_}"
fourth="${remainder%%_*}"; remainder="${remainder#*_}"
Alternativement, vous pouvez utiliser une substitution de paramètre sans guillemets avec expansion générique désactivé et IFS
défini sur le caractère délimiteur (cela ne fonctionne que si le délimiteur est un seul non - caractère d'espacement ou si une séquence d'espaces est un délimiteur).
string='one_two_three_four_five'
set -f; IFS='_'
set -- $string
second=$2; fourth=$4
set +f; unset IFS
Cela détruit les paramètres de position. Si vous effectuez cette opération dans une fonction, seuls les paramètres positionnels de la fonction sont affectés.
Une autre approche consiste à utiliser la fonction intégrée read
.
IFS=_ read -r first second third fourth trail <<'EOF'
one_two_three_four_five
EOF
Je voulais voir une réponse awk
, alors en voici une:
A=$(awk -F_ '{print $2}' <<< 'one_two_three_four_five')
B=$(awk -F_ '{print $4}' <<< 'one_two_three_four_five')
La manière la plus simple (pour les shells avec <<<) est:
IFS='_' read -r a second a fourth a <<<"$string"
Utilisation d'une variable temporelle $a
au lieu de $_
parce qu'un Shell se plaint.
Dans un script complet:
string='one_two_three_four_five'
IFS='_' read -r a second a fourth a <<<"$string"
echo "$second $fourth"
Aucun changement IFS, pas de problèmes avec set -f
(Extension du nom de chemin) Aucune modification des paramètres de position ("$ @").
Pour une solution portable vers tous shells (oui, tous POSIX inclus) sans changer IFS ou set -f
, utilisez l'équivalent hérédoc (un peu plus complexe):
string='one_two_three_four_five'
IFS='_' read -r a second a fourth a <<-_EOF_
$string
_EOF_
echo "$second $fourth"
Comprenez que ces solutions (à la fois ici-doc et l'utilisation de <<<
supprimera toutes les nouvelles lignes de fin.
Et que cela est conçu pour un contenu variable "à une ligne".
Des solutions pour les multilignes sont possibles mais nécessitent des constructions plus complexes.
Une solution très simple est possible dans la version 4.4 de bash
readarray -d _ -t arr <<<"$string"
echo "array ${arr[1]} ${arr[3]}" # array numbers are zero based.
Il n'y a pas d'équivalent pour les shells POSIX, car de nombreux shells POSIX n'ont pas de tableaux.
Pour les shells qui ont des tableaux peuvent être aussi simples que:
(testé en attsh, lksh, mksh, ksh et bash)
set -f; IFS=_; arr=($string)
Mais avec beaucoup de plomberie supplémentaire pour conserver et réinitialiser les variables et les options:
string='one_* *_three_four_five'
case $- in
*f*) noglobset=true; ;;
*) noglobset=false;;
esac
oldIFS="$IFS"
set -f; IFS=_; arr=($string)
if $noglobset; then set -f; else set +f; fi
echo "two=${arr[1]} four=${arr[3]}"
Dans zsh, les tableaux commencent par 1 et ne divisent pas la chaîne par défaut.
Certains changements doivent donc être effectués pour que cela fonctionne dans zsh.
Avec zsh
, vous pouvez diviser la chaîne (sur _
) dans un tableau:
elements=(${(s:_:)string})
puis accéder à chaque élément/tout via un index de tableau:
print -r ${elements[4]}
Gardez à l'esprit que dans zsh
(contrairement à ksh
/bash
) les indices de tableau commencent à 1 .
Une solution python est-elle autorisée?
# python -c "import sys; print sys.argv[1].split('_')[1]" one_two_three_four_five
two
# python -c "import sys; print sys.argv[1].split('_')[3]" one_two_three_four_five
four
n autre exemple awk; plus simple à comprendre.
A=\`echo one_two_three_four_five | awk -F_ '{print $1}'\`
B=\`echo one_two_three_four_five | awk -F_ '{print $2}'\`
C=\`echo one_two_three_four_five | awk -F_ '{print $3}'\`
... and so on...
Peut également être utilisé avec des variables.
Supposons:
this_str = "one_two_three_four_five"
Ensuite, les travaux suivants:
A = `echo $ {this_str} | awk -F_ '{print $ 1}' '
B = `echo $ {this_str} | awk -F_ '{print $ 2}' '
C = `echo $ {this_str} | awk -F_ '{print $ 3}' '
... etc...