web-dev-qa-db-fra.com

Retourne le code de sed sans correspondance

J'utilise sed pour mettre à jour mon fichier de configuration json dans le runtime . Parfois, lorsque le motif ne correspond pas dans le fichier json, sed quitte toujours avec le code retour 0.

Renvoyer 0 signifie que l'opération a abouti, mais pourquoi sed renvoie-t-il 0 s'il ne trouve pas le modèle approprié et met à jour le fichier? Y at-il une solution de contournement pour cela?

Merci!

40
bram

comme @cnicutar a commenté, le code retour d'une commande signifie que la commande a été exécutée avec succès. n'a rien à voir avec la logique que vous avez implémentée dans les codes/scripts.

alors si vous avez:

echo "foo"|sed '/bar/ s/a/b/'

sed retournera 0 mais si vous écrivez des erreurs de syntaxe/expression, ou si le fichier/entrée n'existe pas, sed ne peut pas exécuter votre demande, sed retournera 1.

solution de contournement

ce n'est en fait pas solution de contournement . sed a la commande q: (depuis la page de manuel):

 q [exit-code]

ici, vous pouvez définir le code de sortie que vous voulez. Par exemple, '/foo/!{q100}; {s/f/b/}' quittera avec le code 100 si foo n'est pas présent, sinon, effectuez la substitution f-> b et quittez avec le code 0.

Cas assorti:

kent$  echo "foo" | sed  '/foo/!{q100}; {s/f/b/}'
boo
kent$  echo $?
0

Cas inégalé:

kent$ echo "trash" | sed  '/foo/!{q100}; {s/f/b/}'
trash
kent$ echo $?
100

J'espère que cela répond à votre question.

modifier

Je dois ajouter que l'exemple ci-dessus concerne uniquement le traitement sur une ligne. Je ne connais pas votre exigence exacte. quand vous voulez obtenir exit 1. une ligne sans correspondance ou le fichier entier. Si le cas de fichier entier ne correspond pas, vous pouvez envisager awk, ou même faire un grep avant votre traitement de texte ...

46
Kent

Cela pourrait fonctionner pour vous (GNU sed):

sed '/search-string/{s//replacement-string/;h};${x;/./{x;q0};x;q1}' file

Si le search-string est trouvé, il sera remplacé par replacement-string et à la fin du fichier, sed sera fermé avec le code retour 0. Si aucune substitution n'a lieu, le code de retour sera 1

Une explication plus détaillée:

Dans l'utilisateur sed, l'utilisateur dispose de deux registres: l'espace de modèle (PS) dans lequel la ligne actuelle est chargée (moins le saut de ligne) et un registre de réserve appelé espace de maintien (HS) initialement vide.

L'idée générale est d'utiliser le SH comme un indicateur pour indiquer si une substitution a eu lieu. Si le SH est toujours vide à la fin du fichier, aucune modification n'a été apportée, sinon des modifications sont survenues.

La commande /search-string/ établit une correspondance avec search-string avec tout ce qui se trouve dans le PS. Si elle contient le search-string, les commandes entre les accolades suivantes sont exécutées.

Premièrement, la substitution s//replacement-string/ (sed utilise la dernière expression rationnelle, c'est-à-dire le search-string, si le côté gauche est vide, donc s//replacement-string est identique à s/search-string/replacement-string/), puis la commande h crée une copie du PS et la place dans le SH.

La commande sed $ est utilisée pour reconnaître la dernière ligne d'un fichier et les événements suivants se produisent.

Tout d’abord, la commande x permute les deux registres, de sorte que le SH devient le PS et que le PS devient le HS.

Ensuite, tous les caractères sont recherchés dans le PS. /./ (. signifie que tous les caractères correspondent). Rappelez-vous que le SH (à présent, le PS) était initialement vide jusqu'à ce qu'une substitution ait eu lieu. Si la condition est vraie, la variable x est à nouveau exécutée, suivie de la commande q0 qui met fin à tout le traitement sed et définit le code de retour sur 0. Sinon, la commande x est exécutée et le code de retour est défini sur 1.

N.B. bien que la q abandonne le traitement sed, cela n'empêche pas le PS d'être réassemblé par sed et imprimé comme d'habitude.

Une autre alternative:

sed '/search-string/!ba;s//replacement-string/;h;:a;$!b;p;x;/./Q;Q1' file

ou:

sed '/search-string/,${s//replacement-string/;b};$q1' file
44
potong

Ces réponses sont trop compliquées. Qu'y a-t-il de mal à écrire un peu de script Shell qui utilise grep pour déterminer si l'élément que vous souhaitez remplacer utilise la méthode sed pour le remplacer?

grep -q $TARGET_STRING $file
if [ $? -eq 0 ]
then
    echo "$file contains the old site"
    sed -e "s|${TARGET_STRING}|${NEW_STRING}|g" ....
fi
17
gilbertpilz

Vous trouverez ci-dessous le modèle que nous utilisons avec sed -rn ou sed -r.

La commande de recherche et de remplacement complète ("s/.../.../...") est facultative. Si la recherche et le remplacement sont utilisés, pour des raisons de rapidité et ayant déjà correspondu à $ matchRe, nous utilisons aussi rapidement que possible une valeur $ searchRe, en utilisant. où le caractère n'a pas besoin d'être revérifié et. {$ len} pour les sections de longueur fixe du motif.

La valeur de retour pour no found est $ notFoundExit.

/$matchRe/{s/$searchRe/$replacement/$options; Q}; q$notFoundExit

Pour les raisons suivantes:

  • Pas de perte de temps à tester les cas correspondants et non comparés
  • Pas de temps perdu à copier depuis ou vers les tampons
  • Pas de branches superflues
  • Flexibilité raisonnable

En modifiant le cas des commandes Q, le comportement variera en fonction du moment où l'exit doit avoir lieu. Les comportements impliquant l'application de la logique booléenne à une entrée de ligne multiple nécessitent plus de complexité dans la solution.

1
Douglas Daseeco

J'avais voulu tronquer un fichier en quittant quand la correspondance a été trouvée (et exclure la ligne correspondante). C'est pratique lorsqu'un processus qui ajoute des lignes à la fin du fichier peut être réexécuté. "Q; Q1" n'a pas fonctionné, mais simplement "Q1" comme suit:

si sed -i '/ texte je voulais trouver/Q1' fichier.txt puis insérer une ligne blanche à la fin du fichier + nouvelles lignes fi insérer uniquement les nouvelles lignes sans la ligne blanche

0
Ronnie and Sandy

Comme nous le savons déjà, lorsque sed ne correspond pas, il renvoie simplement sa chaîne d'entrée - aucune erreur ne s'est produite. Il est vrai qu'une différence entre les chaînes d'entrée et de sortie implique une correspondance, mais une correspondance n'implique pas une différence dans les chaînes; après tout, sed aurait simplement pu faire correspondre tous les caractères saisis . La faille est créée dans l'exemple suivant

h=$(echo "$g" | sed 's/.*\(abc[[:digit:]]\).*/\1/g')    
if [ ! "$h" = "$g" ]; then    
  echo "1"   
else    
  echo "2"    
fi

g=Xabc1 donne 1, alors que g=abc1 donne 2; pourtant, sed est la même chose pour ces deux chaînes d'entrée. Il peut donc être difficile de déterminer si sed est compatible ou non. Une solution:

h=$(echo "fix${g}ed" | sed 's/.*\(abc[[:digit:]]\).*/\1/g')
if [ ! "$h" = "fix${g}ed" ]; then    
  echo "1"   
else    
  echo "2"    
fi

dans ce cas, le 1 est imprimé si et seulement si sed correspond.

0
Dave Cole