Indexer une chaîne en bash

14

Comment puis-je faire référence à une chaîne par index dans sh / bash? Autrement dit, 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 de 10 caractères.

Y a-t-il quelque chose comme;

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

Pierre B
la source
5
Pourquoi le bashtag si vous demandez une shsolution?
Stéphane Chazelas

Réponses:

14

Aussi simple que cela.

(frapper)

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

Voila.

Et une explication du Guide de Bash-Scripting Avancé ( Chapitre 10. Manipulation des Variables ) , (avec des NOTEs supplémentaires en ligne pour mettre en évidence les erreurs dans ce manuel):

Extraction de sous-chaîne

${string:position}

Extrait la sous-chaîne de $stringat $position.

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

${string:position:length}

Extrait les $lengthcaractères de la sous-chaîne de $stringat $position.

NOTEcitations manquantes autour des extensions de paramètres! echone 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 de position et de longueur peuvent être "paramétrés", c'est-à-dire représentés comme une variable plutôt que comme une constante numérique.


Si le $stringparamètre est "*" ou "@", cela extrait un maximum de $lengthparamètres de position, à partir de $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 substrest une extension GNU.

expr substr $string $position $length

Extrait les $lengthcaractères à $stringpartir de $position.

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

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

NOTE: C'est echoredondant et le rend encore moins fiable. Utilisez expr substr + "$string1" 1 2.

NOTE: exprretournera 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 Ubuntu en tant que abs-guide.

tomas
la source
Dire "position" est légèrement trompeur car il s'agit en fait d'un décalage, ce qui signifie que ${var:1}cela ne renvoie pas la valeur de varla "1ère position", mais en fait de la 2ème.
Kusalananda
C'est vrai, mais tant que vous n'êtes pas d'accord, il peut y avoir une position zéro. Ce qui ne me pose pas de problème.
9

Dans POSIX sh,

  • "${var%?????}"est $varsupprimé des 5 derniers caractères de fin (ou $vars'il $varcontient moins de 5 caractères)

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

  • "${var%_*}"est $varsupprimé de la chaîne la plus courte qui correspond _*à la fin de $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}c'est la même chose ${var%%pattern}mais en cherchant le motif au début $varde la fin)

Avec zsh:

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

Avec ksh, bashou zsh:

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

Avec bashou zsh:

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

Si vous avez besoin de la shcompatibilité Bourne , 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 $varcontient des octets qui ne peuvent pas faire partie de caractères valides, YMMV.

Stéphane Chazelas
la source
mon, ils ont vraiment trouvé une syntaxe laide pour l'intérieur de ces accolades.
cat
2

shne fournit pas un moyen intégré d'extraire une sous-chaîne d'une chaîne (pour autant que je puisse voir), mais avec bashvous, 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}.

Kusalananda
la source
2

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%??}
choroba
la source
0

Tout d'abord, n'utilisez pas de for boucle 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
MelBurslan
la source
3
Pourquoi est-il mauvais d'utiliser foravec des noms de fichiers?
choroba
Citez vos variables et utilisez printfpour être plus sûr. ... et read -r.
Kusalananda
3
La forboucle de l'OP était correcte sauf peut-être pour les disparus --. Je peux voir au moins 10 bugs dans vos 4 lignes de code! dont beaucoup de mauvaises pratiques bien connues comme supposer que les noms de fichiers sont sur une seule ligne, utiliser l'écho, les guillemets manquants
Stéphane Chazelas