Pourquoi sed me donne-t-il une erreur sur un «s» non terminé?

9

J'ai un ensemble de remplacements sed dans un script bash et j'obtiens une erreur concernant une commande `s 'non terminée. Voici à quoi ressemble la ligne sed:

sed -n -e "s/TMPFOO1/$FOO1/" -e "s/TMPFOO2/$FOO2/" -e "s/TMPFOO3/$FOO3/" -e "s/TMPFOO4/$FOO4/" -e "s/TMPFOO5/$FOO5/" /home/foo/template > /home/foo/template/finishedresult

Pour une raison quelconque, bash n'aime pas cela et j'obtiens une erreur

sed: -e expression #4, char 69: unterminated `s' command

Qu'est-ce que j'oublie ici? Comment puis-je demander à SED de saisir la variable? Il me semble qu'ils sont tous terminés.

Mike B
la source
2
$ FOO4 contient quelque chose de bizarre (ex: "\" ou "\\"?) Qui empêche la commande sed de se terminer. (C'est pourquoi je pense que c'est un "\" de fin, faisant que le prochain "/" soit traité comme une partie de caractère de la chaîne de remplacement, plutôt que comme le caractère de fin pour la commande s)
Olivier Dulac

Réponses:

7

Vous ne pouvez pas interpoler une variable en toute sécurité dans une commande sed, car la substitution est effectuée par le shell, pas par sed. La valeur de la variable devient la syntaxe sed. Par exemple, dans "s/TMPFOO1/$FOO1/", si $FOO1contient une nouvelle ligne, cela provoquera une erreur de syntaxe comme celle que vous avez observée. Si $FOO1contient un /, cela met fin à la scommande et peut provoquer une erreur ou entraîner l'exécution d'autres commandes (si ce qui se trouve après la /syntaxe sed est valide).

Bien que vous puissiez effectuer une première passe de substitution de FOO1pour citer ses caractères spéciaux à inclure dans cette commande sed, il est beaucoup plus simple d'utiliser awk. Awk a une notion de variable et une syntaxe de ligne de commande pour définir la valeur initiale d'une variable.

awk -v FOO1="$FOO1" -v FOO2="$FOO2" -v FOO3="$FOO3" -v FOO4="$FOO4" -v FOO5="$FOO5" '{
    sub(/TMPFOO1/, FOO1);
    sub(/TMPFOO2/, FOO2);
    sub(/TMPFOO3/, FOO3);
    sub(/TMPFOO4/, FOO4);
    sub(/TMPFOO5/, FOO5);
    print;
}' /home/foo/template > /home/foo/template/finishedresult
Gilles 'SO- arrête d'être méchant'
la source
Remarque triviale: - un -vdoit précéder chaque déclaration de variable.
Mike B
@MikeB Merci pour le rapport de bogue. En général, veuillez modifier le message directement lorsque vous trouvez des fautes de frappe comme celle-ci.
Gilles 'SO- arrête d'être méchant'
@Gilles Les modifications de non-auteurs doivent comporter au moins six caractères.
NobleUplift
6

L'une de vos $FOOvariables contient probablement des caractères spéciaux qui sont interprétés par sed.

J'ai une autre version sedqui génère d'autres messages d'erreur mais voici un exemple d'un problème similaire:

$ VAR=a
$ echo i | sed -e "s/i/"$VAR"/"
a
$ tmp> VAR=/
$ echo i | sed -e "s/i/"$VAR"/"
sed: 1: "s/i///
": bad flag in substitute command: '/'

Dans ce cas, $VARcontient un caractère qui est interprété par sedcomme la barre oblique de fin.

Matteo
la source
2

Comme d'autres l'ont mentionné ici, cela dépend du contenu de vos variables FOO *. Dans votre cas, utiliser sedn'est pas le bon choix car il contient probablement des caractères spéciaux.

Jetez un oeil à ce lien et voyez la fonctiongsub_literal

Puisque gsub_literallit depuis stdin et écrit vers stdout, l'utilisation sera:

gsub_literal "$search" "$replace" < /home/foo/template > /home/foo/template/finishedresult

Exemple de sortie:

rany$ cat > foo.txt
a'
a'

rany$ gsub_literal a\' b < foo.txt 
b
b
Rany Albeg Wein
la source
1

Le problème a été résolu pour moi en essayant des barres obliques inverses supplémentaires dans la sed 's/.../.../g'commande. Cette commande

sed 's/\"a/ä/g' input_file

m'a donné ce message d'erreur

sed: -e expression # 1, caractère 9: commande `s 'non terminée

quand il a été exécuté dans le cadre d'un script c-shell, et il l'a fait uniquement avec une version récente de sed, pas avec une version plus ancienne. (Étrangement, la même commande fonctionne bien quand elle est donnée sur la ligne de commande (dans un shell tc)).

Le problème avec le script c-shell a été résolu en faisant précéder le äcaractère d'une barre oblique inverse:

sed 's/\"a/\ä/g' input_file
user3346151
la source