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?
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?
Réponses:
Dans un shell POSIX, la syntaxe ${t:-2}
signifie quelque chose de différent - elle se développe à la valeur de t
if t
est définie et non nulle, et sinon à la valeur 2
. Pour ajuster un seul caractère par développement de paramètre, la syntaxe que vous souhaitez probablement est la suivante:${t%?}
Notez que ksh93
, bash
ou zsh
, ${t:(-2)}
ou ${t: -2}
(notez l'espace) sont légal comme l' expansion de sous - chaîne , mais probablement pas ce que vous voulez, car ils retournent la sous - chaîne commençant à une position 2 caractères à partir de la fin (il supprime le premier caractère i
du chaîne ijk
).
Reportez-vous à la section Extension des paramètres de shell du Manuel de référence de Bash pour plus d'informations:
${parameter%word}
supprime le suffixe le plus court correspondant word
- voir la section Expansion des paramètres deman bash
Avec bash
4.2 et plus, vous pouvez faire:
${var::-1}
Exemple:
$ a=123
$ echo "${a::-1}"
12
Notez que pour les anciens bash
(par exemple, bash 3.2.5
sous OS X), vous devez laisser des espaces entre et après les deux points:
${var: : -1}
bash
version 4.2-alpha et supérieure, dommage que la version à laquelle j'ai accès soit antérieure. : - /
${var:offset:lenght}
été ajoutée uniquement dans bash 4.2
. Peut-être que OSX ajoute son propre patch pour bash
.
pour supprimer les derniers n
caractères d'une ligne qui ne fait pas usage de sed
OU awk
:
> echo lkj | rev | cut -c (n+1)- | rev
Ainsi, par exemple, vous pouvez supprimer le dernier caractère en one character
utilisant ceci:
> echo lkj | rev | cut -c 2- | rev
> lk
depuis la rev
page de manuel:
DESCRIPTION
L'utilitaire rev copie les fichiers spécifiés sur la sortie standard en inversant l'ordre des caractères dans 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
En utilisant sed, il devrait être aussi rapide que
sed 's/.$//'
Votre seul écho est alors echo ljk | sed 's/.$//'
.
En utilisant cela, la chaîne d'une ligne pourrait avoir n'importe quelle taille.
Quelques options en fonction du shell:
t=${t%?}
t=`expr " $t" : ' \(.*\).'`
t=${t[1,-2]}
t=${t:0:-1}
t=${t:0:${#t}-1}
t=${t/%?}
t=${t/~(E).$/}
@ {t=$1} ~~ $t *?
Notez que bien que tous soient supposés effacer 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 (ce qui risquerait donc de corrompre le dernier caractère s'il était multi-octets. ).
La expr
variante suppose que $t
ne se termine pas par plus d'un caractère de nouvelle ligne. Il retournera également un statut de sortie non nul si la chaîne résultante finit par être 0
( 000
ou même -0
avec certaines implémentations). Cela pourrait également donner des résultats inattendus si la chaîne contient des caractères non valides.
t=${t%?}
n'est pas Bourne mais vous ne rencontrerez probablement pas un shell Bourne de nos jours. ${t%?}
fonctionne dans tous les autres cependant.
fish
est en cours. La version 2.3.0 qui a introduit la fonction string
intégrée n’a pas été publiée au moment de la période de questions. Avec la version que je teste, il vous faut string replace -r '(?s).\z' '' -- $t
(et je m'attendrais à ce qu'ils veuillent changer ça, ils devraient changer les drapeaux qu'ils passent à PCRE) ou plus compliqués. Il traite également mal les caractères de nouvelle ligne, et je sais qu'ils envisagent de changer cela également.
La réponse la plus portable et la plus courte est presque certainement:
${t%?}
Cela fonctionne en bash, sh, ash, dash, busybox / ash, zsh, ksh, etc.
Cela fonctionne en utilisant l'expansion des paramètres de shell old-school. Spécifiquement, le %
spécifie de supprimer le plus petit suffixe correspondant du paramètre t
qui correspond au motif global ?
(c'est-à-dire: n'importe quel caractère).
Voir "Supprimer le plus petit modèle de suffixe" ici pour une explication (beaucoup) plus détaillée et plus de fond. Consultez également la documentation de votre shell (par exemple:) man bash
sous "Développement des paramètres".
En guise de remarque, si vous souhaitez supprimer le premier caractère à la place, vous utiliserez ${t#?}
, puisque les #
correspondances se trouvent à l'avant de la chaîne (préfixe) au lieu de l'arrière (suffixe).
Il faut également noter que les deux %
et #
ont %%
et ##
versions, qui correspondent à la plus longue version du motif donné au lieu de la plus courte. Les deux ${t%%?}
et ${t##?}
feraient la même chose que leur opérateur unique dans ce cas, cependant (alors n’ajoutez pas le caractère supplémentaire inutile). En effet, le ?
modèle donné ne correspond qu’à un seul caractère. Ajoutez des *
éléments non génériques et les choses deviennent plus intéressantes avec %%
et ##
.
Comprendre les développements de paramètres, ou au moins connaître leur existence et savoir les rechercher, est extrêmement utile pour écrire et déchiffrer des scripts shell de nombreuses versions. Les extensions de paramètres ressemblent souvent à des arcanes dans un shell voodoo parce que ... bien ... ce sont des arcanes dans un vaudou (bien que très bien documentées si vous savez rechercher "une expansion des paramètres"). C'est vraiment bien d'avoir dans la ceinture à outils quand on est coincé dans une coquille, cependant.
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
estdash
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 l' -
option principale . C'est le cas de head
celui fourni avec OS X.
Juste pour compléter quelques utilisations possibles de pure bash:
#!/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 la suivante:
pour la seconde, remarquez le signe, ce qui signifie 'depuis la fin de la ligne' et la syntaxe est
${STRING:OFFSET:LENGTH}
%
${STRING/PATTERN/SUBSTITUTION}
Et voici deux formes plus courtes de ce qui précède
echo "Removed trailing whitespace: '${STR::-1}'"
echo "Removed trailing whitespace: '${STR%\ }'"
Ici encore, remarquez le %
signe, signifiant 'Supprimer (c'est-à-dire, remplacer par' ') le motif correspondant le plus court (ici représenté par un espace d'échappement' \ ' à la fin du paramètre PARAMETER - ici nommé STR
Comme nous pouvons également utiliser php en ligne de commande, ou des scripts shell. C'est parfois utile pour l'analyse syntaxique chirurgicale.
php -r "echo substr('Hello', 0, -1);"
// Output hell
Avec tuyauterie:
echo "hello" | php -r "echo substr(trim(fgets(STDIN)), 0, -1);"
// Output hell