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.
Je suggère deux améliorations:
N'empilez pas les appels à sed
comme vous le faites, mais regroupez-les tous dans une seule fonction, comme escape_string
ci-dessous.
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"
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).
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'
où original_value = "includes_special_char_ /" new_value = "includes_new_special_char:"
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