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


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.


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.


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}.


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%??}

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

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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.