web-dev-qa-db-fra.com

Indexer une chaîne en bash

Comment puis-je faire référence à une chaîne par index dans sh/bash? C'est-à-dire, le séparer essentiellement.

J'essaie de supprimer 5 caractères d'un nom de fichier. Tous les noms ont la structure: nom_nr_code. J'essaie de supprimer le bit de code alphanumérique 5. name_nr_ est toujours composé de 10 caractères.

Y a-t-il quelque chose comme;

for i in * ; do mv "$i" "$i"[:10] ; done

15
Pierre B

Aussi simple que cela.

(frapper)

for i in * ; do mv -- "$i" "${i:0:5}" ; done

Voila.

Et une explication de Advanced Bash-Scripting Guide ( Chapter 10. Manipulating Variables ), (with extra NOTEs en ligne pour souligner les erreurs dans ce manuel):

Extraction de sous-chaîne

${string:position}

Extrait la sous-chaîne de $string à $position.

Si la $string le paramètre est "*" ou "@", puis cela extrait les paramètres de position, en commençant à $position.

${string:position:length}

Extrait $length caractères de la sous-chaîne de $string à $position.

NOTE citations manquantes autour des extensions de paramètres! echo ne doit pas être utilisé pour des données arbitraires.

stringZ=abcABC123ABCabc
#       0123456789.....
#       0-based indexing.

echo ${stringZ:0}                       # abcABC123ABCabc
echo ${stringZ:1}                       # bcABC123ABCabc
echo ${stringZ:7}                       # 23ABCabc 

echo ${stringZ:7:3}                     # 23A
                                        # Three characters of substring.


# Is it possible to index from the right end of the string?

echo ${stringZ:-4}                      # abcABC123ABCabc
# Defaults to full string, as in ${parameter:-default}.
# However . . . 

echo ${stringZ:(-4)}                    # Cabc
echo ${stringZ: -4}                     # Cabc
# Now, it works.
# Parentheses or added space "escape" the position parameter.

Les arguments position et length peuvent être "paramétrés", c'est-à-dire représentés comme une variable plutôt que comme une constante numérique.


Si la $string le paramètre est "*" ou "@", puis cela extrait un maximum de $length paramètres de position, commençant à $position.

echo ${*:2}          # Echoes second and following positional parameters.
echo ${@:2}          # Same as above.

echo ${*:2:3}        # Echoes three positional parameters, starting at second.

NOTE: expr substr est une extension GNU.

expr substr $string $position $length

Extrait $length caractères de $string à partir de $position.

stringZ=abcABC123ABCabc
#       123456789......
#       1-based indexing.

echo `expr substr $stringZ 1 2`           # ab
echo `expr substr $stringZ 4 3`           # ABC

NOTE: Ce echo est redondant et le rend encore moins fiable. Utilisez expr substr + "$string1" 1 2.

NOTE: expr retournera avec un état de sortie non nul si la sortie est 0 (ou -0, 00 ...).


BTW. Le livre est présent dans le référentiel officiel d'Ubuntu en tant que abs-guide.

16
user147505

Dans POSIX sh,

  • "${var%?????}" est $var dépouillé des 5 derniers caractères de fin (ou $var si $var contient moins de 5 caractères)

  • "${var%"${var#??????????}"}" correspond aux 10 premiers caractères de $var.

  • "${var%_*}" est $var dépouillé de la chaîne la plus courte qui correspond à _* au bout du $var (foo_bar_baz -> foo_bar).
  • "${var%%_*}": correspondance identique mais la plus longue au lieu de la correspondance la plus courte (foo_bar_baz -> foo).
  • si vous vouliez obtenir foo_bar_: "${var%"${var##*_}"}" (${var##pattern} est le même que ${var%%pattern} mais en cherchant le motif au début de $var au lieu de la fin).

Avec zsh:

  • $var[1,-6] pour le premier caractère au 6e depuis la fin (donc tous sauf les 5 derniers).
  • $var[1,10] pour les 10 premiers caractères.

Avec ksh, bash ou zsh:

  • "${var:0:10}": 10 premiers caractères de $var

Avec bash ou zsh:

  • "${var:0:-5}": tous sauf les 5 derniers caractères (donne une erreur et quitte le script si $var est défini mais contient moins de 5 caractères, également lorsque $var n'est pas défini avec zsh).

Si vous avez besoin de la compatibilité Bourne sh, c'est très difficile à faire de manière fiable. Si vous pouvez garantir que le résultat ne se terminera pas par des caractères de nouvelle ligne, vous pouvez le faire:

first_10=`expr " $var" : ' \(.{1,10\}\)'` # beware the exit status
                                          # may be non-zero if the
                                          # result is 0 or 0000000000

all_but_last_5=`expr " $var" : ' \(.*\).\{5\}'`

Vous aurez également une limite sur la longueur de $var (variant selon les systèmes).

Dans toutes ces solutions, si $var contient des octets qui ne peuvent pas faire partie de caractères valides, YMMV.

9
Stéphane Chazelas

sh ne fournit pas un moyen intégré d'extraire une sous-chaîne d'une chaîne (pour autant que je sache), mais avec bash vous pouvez le faire

${i:0:10}

Cela vous donnera les dix premiers caractères de la valeur de la variable i.

Le format général est ${variable:offset:length}.

2
Kusalananda

La plupart des shells prennent en charge une sorte d'extension des paramètres qui peut vous aider. En bash, vous pouvez utiliser

substr=${string:4:5} # start at position 4, length 5.

Dans dash, les décalages ne sont pas pris en charge, mais vous pouvez utiliser des modèles de début et de fin:

remove_first3=${string#???}
remove_last2=${string%??}
2
choroba

Tout d'abord, n'utilisez pas de boucle for pour les noms de fichiers.

Ensuite, quelque chose comme ça devrait aider.

find ./ -type f | while read filename ;do
  newfilename=$(echo ${filename}|cut -c 1-10)
  mv ${filename} ${newfilename}
done
0
MelBurslan