web-dev-qa-db-fra.com

Remplacement de caractères spéciaux dans un script Shell à l'aide de sed

J'essaie d'écrire un script Shell qui remplacera les caractères/chaînes que je choisirai avec sed. Ma première tentative a fonctionné à l'exception des caractères spéciaux. J'ai essayé d'utiliser sed pour corriger les caractères spéciaux afin qu'ils soient également recherchés ou remplacés. J'ai décidé de simplifier le script afin de tester les objectifs et de ne traiter qu'un seul personnage incriminé. Cependant, j'ai toujours des problèmes.

Script édité

#! /bin/sh
oldString=$1
newString=$2
file=$3

oldStringFixed=$(echo "$oldString" | sed 's/\\/\\\\/g')
oldStringFixed=$(echo "$oldStringFixed" | sed 's/\[/\\\[/g')
oldStringFixed=$(echo "$oldStringFixed" | sed 's/\]/\\\]/g')
oldStringFixed=$(echo "$oldStringFixed" | sed 's/\^/\\\^/g')
oldStringFixed=$(echo "$oldStringFixed" | sed 's/\*/\\\*/g')
oldStringFixed=$(echo "$oldStringFixed" | sed 's/\+/\\\+/g')
oldStringFixed=$(echo "$oldStringFixed" | sed 's/\./\\\./g')
oldStringFixed=$(echo "$oldStringFixed" | sed 's/\$/\\\$/g')
oldStringFixed=$(echo "$oldStringFixed" | sed 's/\-/\\\-/g')

sed -e "s/$oldStringFixed/$newString/g" "$file" > newfile.updated
mv newfile.updated "$file"#! /bin/sh

Au cas où ce ne serait pas clair, j'essayerais de chercher dans oldString le caractère [ de le remplacer par une version échappée et d'assigner les résultats à oldStringFixed (ai-je besoin des correctifs pour cela?). Les deux dernières lignes sont des versions légèrement modifiées de mon script original qui, à mon avis, fonctionnent correctement.

Lorsque je répète la chaîne fixe, rien ne s'affiche et sed génère une erreur

sed: can't read [: No such file or directory

Quelqu'un peut-il expliquer ce qui ne va pas avec ma première ligne sed?

MODIFIER:

Grâce à Jite, le script fonctionne mieux. Cependant, je ne parviens toujours pas à remplacer les caractères entre guillemets simples par des espaces, c'est-à-dire '*'. La nouvelle version est ci-dessus.

5
user3074091

Je suggère deux améliorations:

  1. N'empilez pas les appels à sed comme vous le faites, mais regroupez-les tous dans une seule fonction, comme escape_string ci-dessous.

  2. Vous pouvez utiliser un délimiteur de fantaisie pour la commande sed substitute afin d'éviter que des problèmes liés à / fassent partie des chaînes impliquées.

Avec ces modifications, votre script ressemble à:

#! /bin/sh
oldString="$1"
newString="$2"
file="$3"

escape_string()
{
   printf '%s' "$1" | sed -e 's/[][\\^*+.$-]/\\\1/g'
}

fancyDelim=$(printf '\001')

oldStringFixed=$(escape_string "$oldString")
sed -e "s$fancyDelim$oldStringFixed$fancyDelim$newString${fancyDelim}g" "$file" \
  > newfile.updated
mv newfile.updated "$file"
3

Changement:

oldStringFixed= `sed 's/\[/\[/g' "$oldString"\`

à:

oldStringFixed=$(echo "$oldString" | sed 's/\[/\\\[/g')

Problème 1: l'espace après le = n'est pas autorisé lors de l'affectation de variables Shell.

Problème 2: sed attend un fichier en entrée, pas une chaîne. Vous pouvez le diriger comme le fait ma solution.

Problème 3: Vous devez d'abord échapper à la barre oblique inverse \\, puis échapper à votre caractère \[, totalisant \\\[ :)

Note latérale: j'ai changé `` en $ () car ce dernier est la praxis recommandée (en raison de l'imbrication, un autre sujet).

1
Jite

To remplace les valeurs contenant des caractères spéciaux essayez d'utiliser sed avec "|" au lieu de "/"

Exemple: sed -i 's |' $ original_value '|' $ new_value '| g'

original_value = "includes_special_char_ /" new_value = "includes_new_special_char:"

0
Sushant Dhingra

Pour moi, c’était un cauchemar d’essayer d’être séduit pour le cas général. J'ai abandonné et écrit un court code Python pour remplacer sed:

#!/usr/bin/python
# replace.py
import sys

# Replace string in a file (in place)
match=sys.argv[1]
replace=sys.argv[2]
filename=sys.argv[3]

print "Replacing strings in",filename

with open(filename,"r") as f:
  data = f.read().replace(match,replace)

with open(filename,"w") as f:
  f.write(data)

Ce qui peut alors être utilisé comme:

#!/bin/bash
orig='<somethinghorrible>'
out='<replacement>'
python replace.py "$orig" "$out" myfile.txt
0
Ben Farmer