1
votes

Remplacez les espaces par ~ in (ba) sh sans commande externe

J'ai une chaîne qui peut contenir plusieurs espaces (et tabulations) et se terminer également par des espaces (mais elle ne commencera jamais par des espaces).

Quelque chose comme: "topo pippo pluto"

Je dois supprimer les espaces à la fin et remplacer toute séquence d'espaces restante par ~ . Dans l'exemple précédent, j'obtiendrais "topo~pippo~pluto".

Je le fais actuellement avec:

mystring=$(echo "$mystring" | sed -e 's/\s\s*/~/g' -e 's/~~*$//' ) 


0 commentaires

3 Réponses :


3
votes

Avec Bash:

$ shopt -s extglob
$ str='topo pippo    pluto   '
$ str=${str%%+([[:blank:]])}
$ echo "<$str>"
<topo pippo    pluto>
$ str=${str//+([[:blank:]])/'~'}
$ echo "<$str>"
<topo~pippo~pluto>

L'option extglob est requise pour activer le modèle + (pattern) . $ {str %% + ([[: blank:]])} supprime tous les espaces à la fin de la chaîne; $ {str // + ([[: blank:]]) / '~'} remplace toutes les séries de blancs par un ~ .

p >


3 commentaires

Utilisez + ([[: space:]]) pour remplacer les tabulations et espaces.


Merci! J'ai complètement raté l'existence d'extglob! Comme première transformation, j'ai dû ajouter str = $ {str // /} (il y a un caractère de tabulation juste après les deux barres obliques) pour traiter les onglets. Ensuite, cela a parfaitement fonctionné!


@hmm Ou [[: blank:]] - [[: space:]] comprend quelques éléments supplémentaires en plus des blancs et des espaces.



2
votes

Il est expliqué dans la documentation de bash (exécutez man bash sur votre terminal) sous la section "Extension des paramètres":

${parameter/pattern/string}

Substitution de modèle . Le modèle est développé pour produire un modèle comme dans l'expansion des chemins. Le Paramètre est développé et la plus longue correspondance de pattern par rapport à sa valeur est remplacée par string .
Si pattern commence par / , toutes les correspondances de pattern sont remplacées par string . Normalement, seule la première correspondance est remplacée.
Si le modèle commence par # , il doit correspondre au début de la valeur développée du paramètre .
Si le motif commence par % , il doit correspondre à la fin de la valeur développée du paramètre .
Si string est nul, les correspondances du modèle sont supprimées et le / modèle suivant peut être omis.
Si le paramètre est @ ou * , l'opération de substitution est appliquée à chaque paramètre de position à son tour, et le développement est la liste résultante.
Si paramètre est une variable de tableau indicée avec @ ou * , l'opération de substitution est appliquée à chaque membre du tableau à son tour, et l'expansion est la liste résultante.

Vous ne pouvez pas faire les deux remplacements en une seule commande, vous devez l'utiliser deux fois (une fois pour remplacer les séquences d'espaces par ~ et une fois pour supprimer le dernier ~ :

X="topo pippo    pluto   "

# Enable the extended pattern matching
shopt -s extglob

# Replace the sequences of spaces with ~
Y="${X//+( )/\~}"
echo "[$Y]"          # prints: [topo~pippo~pluto~]

# Replace the trailing ~
Z="${Y%\~}"
echo "[$Z]"          # prints: [topo~pippo~pluto]

Remarques:

  • Les crochets dans les instructions echo ci-dessus n'ont pas de signification particulière. Je les ai utilisés pour montrer clairement les limites des chaînes.
  • ~ est un symbole spécial dans Bash et dans d'autres shells. Cela signifie le répertoire personnel de l'utilisateur et il est remplacé par sa valeur réelle. Il doit être échappé pour se représenter.
  • + () est un motif étendu (cela signifie "un ou plusieurs des motifs présents entre parenthèses"); cela ne fonctionne que lorsque l'option shell extglob est activée (en utilisant shopt ); apparemment, il est activé par défaut, mais dans les scripts, vous ne pouvez pas vous fier aux valeurs par défaut; vous feriez mieux de le configurer pour être sûr qu'il fonctionne;
  • $ {Y% \ ~} est une autre extension de paramètre (elle est également expliquée dans la documentation); il supprime de $ Y le dernier suffixe correspondant ( ~ ); comme expliqué ci-dessus, ~ doit être échappé ( \ ~ ) pour être interprété comme lui-même et non comme le répertoire de base.


0 commentaires

3
votes

Une solution shell POSIX:

#!/usr/bin/env sh

mystring="topo pippo    pluto   "

# Disable pathname expansion so the parameters expansion
# will not capture pathes if mystring contains patterns
set -f

# Feed mystring as arguments list
# where each space separated element (word) is an argument
set -- $mystring

# Restore pathname expansion
set +f

# Set ~ as the field separator
IFS='~'

# Expand the parameters into mystring with ~ as separator
mystring="$*"

# Restore the default field separator
unset IFS

echo "$mystring" # Print topo~pippo~pluto


0 commentaires