Remplacer un personnage par un autre dans Bash

223

Je dois pouvoir faire est de remplacer un espace ( ) par un point ( .) dans une chaîne en bash.

Je pense que ce serait assez simple, mais je suis nouveau donc je ne peux pas comprendre comment modifier un exemple similaire pour cette utilisation.

Brian Leishman
la source

Réponses:

390

Utilisez le remplacement de chaîne de shell en ligne. Exemple:

foo="  "

# replace first blank only
bar=${foo/ /.}

# replace all blanks
bar=${foo// /.}

Voir http://tldp.org/LDP/abs/html/string-manipulation.html pour plus de détails.

Brian Clapper
la source
1
Bien que cette solution soit bonne lorsqu'il s'agit de chaînes courtes (le cas courant, je suppose), on peut préférer trles chaînes longues. Sur mon système, il trsurpasse les performances de bash en commençant par des chaînes de plus de 1000caractères. Il semble que la complexité temporelle de bash soit pire que linéaire. Un petit test: x="$(tr -dc 'a-z \n' </dev/urandom | head -c1M)"; time y="$(tr ' ' \\- <<< "$x")"; time z="${x// /-}". Avec une longueur de chaîne de 1M (= 2 ^ 20) a trpris 0.04set bash 5.0.11 a pris 17s. Avec 2M a trpris 0.07s(attendu) mais bash a pris 69s(4 fois plus longtemps pour deux fois la longueur de la chaîne).
Socowi
@Socowi Jouer avec 1 Mo stocké dans une variable n'est pas vraiment habituel! Jusqu'à plus de 10 Ko, bash semble rester plus rapide que bifurquer tr! ... En fonction de la mémoire disponible et des ressources matérielles ... Mais vous avez raison!: Selon le type de travail à faire, les outils dédiés restent plus efficaces!
F.Hauri
Pour les caractères échappés comme les sauts de ligne, assurez-vous de rechercher$'\n'
user2561747
75

Vous pouvez utiliser tr, comme ceci:

tr " " .

Exemple:

# echo "hello world" | tr " " .
hello.world

De man tr:

DESCRIPTION
     Traduire, presser et / ou supprimer des caractères de l'entrée standard, en écrivant sur la sortie standard.

aioobe
la source
Bien que cela fonctionne pour la question telle qu'elle a été posée, elle est moins générale que la réponse acceptée (qui fonctionne sur le remplacement de caractères et également sur des chaînes arbitraires), et elle implique également une commande externe.
Dan Dascalescu
2
D'un autre côté, cela fonctionne sur un fichier de 2 Go sans charger le tout en mémoire.
aioobe
La question portait sur "une chaîne en bash", et non sur des fichiers arbitrairement volumineux.
Dan Dascalescu
52

En bash, vous pouvez effectuer un remplacement de modèle dans une chaîne avec la ${VARIABLE//PATTERN/REPLACEMENT}construction. Utilisez juste /et non //pour remplacer uniquement la première occurrence. Le modèle est un modèle générique, comme les globes de fichiers.

string='foo bar qux'
one="${string/ /.}"     # sets one to 'foo.bar qux'
all="${string// /.}"    # sets all to 'foo.bar.qux'
Gilles 'SO- arrête d'être méchant'
la source
24

Essaye ça

 echo "hello world" | sed 's/ /./g' 
Rob
la source
6

Utilisez la substitution de paramètres:

string=${string// /.}
Fritz G. Mehner
la source
4

Essayez ceci pour les chemins:

echo \"hello world\"|sed 's/ /+/g'|sed 's/+/\/g'|sed 's/\"//g'

Il remplace l'espace à l'intérieur de la chaîne entre guillemets doubles par un +chant, puis remplace le +signe par une barre oblique inverse, puis supprime / remplace les guillemets doubles.

J'ai dû l'utiliser pour remplacer les espaces dans l'un de mes chemins dans Cygwin.

echo \"$(cygpath -u $JAVA_HOME)\"|sed 's/ /+/g'|sed 's/+/\\/g'|sed 's/\"//g'
dsrdakota
la source
2
Il existe déjà une réponse vieille de deux ans qui résout le problème sed. Les citations ne sont pas pertinentes.
chepner