web-dev-qa-db-fra.com

Supprimer le dernier caractère d'une chaîne à l'aide de la manipulation de chaînes dans le script Shell

Je voudrais supprimer le dernier caractère d'une chaîne, j'ai essayé ce petit script:

#! /bin/sh 

t="lkj"
t=${t:-2}
echo $t

mais il affiche "lkj", qu'est-ce que je fais mal?

207
user3581976

Dans un shell POSIX, la syntaxe ${t:-2} Signifie quelque chose de différent - elle se développe à la valeur de t si t est définie et non nulle, et sinon à la valeur 2. Pour découper un seul caractère par expansion de paramètre, la syntaxe que vous souhaitez probablement est ${t%?}

Notez que dans ksh93, bash ou zsh, ${t:(-2)} ou ${t: -2} (Notez l'espace) sont légaux en tant qu'extension de sous-chaîne mais ne sont probablement pas ce que vous voulez, car ils retournent la sous-chaîne à partir d'une position à 2 caractères de la fin (c'est-à-dire qu'elle supprime le premier caractère i de la chaîne ijk).

Voir la section Expansion des paramètres du shell du manuel de référence Bash pour plus d'informations:

122
steeldriver

Avec bash 4.2 et supérieur, vous pouvez faire:

${var::-1}

Exemple:

$ a=123
$ echo "${a::-1}"
12

Notez que pour les anciens bash (par exemple, bash 3.2.5 sur OS X), vous devez laisser des espaces entre et après les deux-points:

${var: : -1}
211
cuonglm

L'utilisation de sed devrait être aussi rapide que

sed 's/.$//'

Votre single echo est alors echo ljk | sed 's/.$//'.
En utilisant cela, la chaîne d'une ligne peut être de n'importe quelle taille.

70
1111161171159459134

pour supprimer les derniers n caractères d'une ligne qui n'utilise pas sed OR awk:

> echo lkj | rev | cut -c (n+1)- | rev

par exemple, vous pouvez supprimer le dernier caractère one character en utilisant ceci:

> echo lkj | rev | cut -c 2- | rev

> lk

à partir de la page de manuel de rev:

LA DESCRIPTION
L'utilitaire rev copie les fichiers spécifiés sur la sortie standard, inversant l'ordre des caractères sur chaque ligne. Si aucun fichier n'est spécifié, l'entrée standard est lue.

MISE À JOUR:

si vous ne connaissez pas la longueur de la chaîne, essayez:

$ x="lkj"
$ echo "${x%?}"
lk
70
Nidal

Quelques options selon le Shell:

  • POSIX: t=${t%?}
  • Bourne: t=`expr " $t" : ' \(.*\).'`
  • zsh/yash: t=${t[1,-2]}
  • bash/zsh: t=${t:0:-1}
  • ksh93/bash/zsh/mksh: t=${t:0:${#t}-1}
  • ksh93/bash/zsh/mksh: t=${t/%?}
  • ksh93: t=${t/~(E).$/}
  • es: @ {t=$1} ~~ $t *?

Notez que bien que tous soient censés supprimer le dernier caractère, vous constaterez que certaines implémentations (celles qui ne prennent pas en charge les caractères multi-octets) suppriment le dernier octet à la place (ainsi corromprait probablement le dernier caractère s'il était multi-octet).

La variante expr suppose que $t Ne se termine pas par plus d'un caractère de nouvelle ligne. Il retournera également un état de sortie non nul si la chaîne résultante finit par être 0 (Ou 000 Ou même -0 Avec certaines implémentations). Il pourrait également donner des résultats inattendus si la chaîne contient des caractères non valides.

50
Stéphane Chazelas

La réponse la plus portable et la plus courte est presque certainement:

${t%?}

Cela fonctionne dans bash, sh, ash, dash, busybox/ash, zsh, ksh, etc.

Il fonctionne en utilisant l'expansion des paramètres Shell à l'ancienne. Plus précisément, le % Spécifie de supprimer le plus petit suffixe correspondant du paramètre t qui correspond au modèle global ? (C'est-à-dire n'importe quel caractère).

Voir "Supprimer le plus petit motif de suffixe" ici pour une explication (beaucoup) plus détaillée et plus d'informations. Consultez également la documentation de votre shell (par exemple: man bash) Sous "Extension des paramètres".


En remarque, si vous vouliez supprimer le premier caractère à la place, vous utiliseriez ${t#?}, Car # correspond à l'avant de la chaîne (préfixe) au lieu de l'arrière (suffixe).

Il convient également de noter que les versions % Et # Et %% Et ##, Qui correspondent aux plus longues version du modèle donné au lieu de la plus courte. ${t%%?} Et ${t##?} Feraient tous les deux la même chose que leur opérateur unique dans ce cas, (donc n'ajoutez pas le caractère supplémentaire inutile). Cela est dû au fait que le modèle ? Donné ne correspond qu'à un seul caractère. Mélangez un * Avec des caractères non génériques et les choses deviennent plus intéressantes avec %% Et ##.

Comprendre les extensions de paramètres, ou du moins connaître leur existence et savoir comment les rechercher, est incroyablement utile pour écrire et déchiffrer des scripts Shell de nombreuses versions. Les extensions de paramètres ressemblent souvent à des arcanes vaudou Shell pour beaucoup de gens parce que ... eh bien ... ils sont arcanes vaudou Shell (bien que très bien documentés si vous connaissez rechercher "expansion des paramètres"). Certainement bien d'avoir dans la ceinture à outils lorsque vous êtes coincé dans un Shell, cependant.

36
Russ
t=lkj
echo ${t:0:${#t}-1}

Vous obtenez une sous-chaîne de 0 à la longueur de chaîne -1. Notez cependant que cette soustraction est spécifique à bash et ne fonctionnera pas sur d'autres shells.

Par exemple, dash n'est pas capable d'analyser même

echo ${t:0:$(expr ${#t} - 1)}

Par exemple, sur Ubuntu, /bin/sh est dash

18
Ángel

Vous pouvez également utiliser head pour imprimer tout sauf le dernier caractère.

$ s='i am a string'
$ news=$(echo -n $s | head -c -1)
$ echo $news
i am a strin

Mais malheureusement, certaines versions de head n'incluent pas le premier - option. C'est le cas pour le head fourni avec OS X.

15
greenbeansugar

Il est assez facile de le faire en utilisant une expression régulière:

n=2
echo "lkj" | sed "s/\(.*\).\{$n\}/\1/"
6
unxnut

Merci SteelDriver et Networker!

si vous ne connaissez pas la longueur de la chaîne, essayez:

$ x="lkj"
$ echo "${x%?}"
lk
6
drill

Quelques raffinements. Pour supprimer plusieurs caractères, vous pouvez ajouter plusieurs points d'interrogation. Par exemple, pour supprimer les deux derniers caractères de la variable: $SRC_IP_MSG, vous pouvez utiliser:

SRC_IP_MSG=${SRC_IP_MSG%??}
6
yuliskov

Juste pour compléter quelques utilisations possibles de bash pur:

#!/bin/bash

# Testing substring removal
STR="Exemple string with trailing whitespace "
echo "'$STR'"
echo "Removed trailing whitespace: '${STR:0:${#STR}-1}'"
echo "Removed trailing whitespace: '${STR/%\ /}'"

La première syntaxe prend une sous-chaîne d'une chaîne, la syntaxe est
${STRING:OFFSET:LENGTH}
Pour le second, notez le % signe, ce qui signifie "de fin de ligne" et la syntaxe est
${STRING/PATTERN/SUBSTITUTION}

Et voici deux formes plus courtes de celles mentionnées ci-dessus

echo "Removed trailing whitespace: '${STR::-1}'"
echo "Removed trailing whitespace: '${STR%\ }'"

Ici, remarquez à nouveau le % signe, signifiant 'Supprimer (c'est-à-dire remplacer par' ') le motif correspondant le plus court (ici représenté par un espace d'échappement '\' à partir de la fin du paramètre [~ # ~] [~ # ~] - ici nommé [~ # ~] str [~ # ~]

4
CermakM

Comme nous pouvons également utiliser php en ligne de commande, ou des scripts Shell. Il est parfois utile pour l'analyse chirurgicale.

php -r "echo substr('Hello', 0, -1);" 
// Output hell

Avec passepoil:

echo "hello" | php -r "echo substr(trim(fgets(STDIN)), 0, -1);"
// Output hell
1
NVRM