web-dev-qa-db-fra.com

Comment utiliser sed avec des variables de chemin de fichier ET des rappels regex ET des expressions arithmétiques

J'ai beaucoup de mal à obtenir la syntaxe appropriée en utilisant sed avec des variables contenant un chemin de fichier, un rappel regex et une expression arithmatique. Je ne sais pas comment échapper correctement aux choses.

J'ai un chemin de fichier dans un fichier texte avec un numéro à côté. Je veux trouver cette ligne et incrémenter le nombre.

FILE="/home/username/scripts/test.txt"
LINE="/home/username/Pictures/properties/wallpaper/span/tree.jpg"

sed -i -e "s,'$LINE' \([0-9]*\),'$LINE' $((\1+1))," $FILE

Par exemple..

/home/username/Pictures/properties/wallpaper/span/tree.jpg 2

devraient devenir..

/home/username/Pictures/properties/wallpaper/span/tree.jpg 3

Quelle est la meilleure façon d'échapper au "." dans le chemin du fichier? Comment puis-je implémenter correctement le rappel \1 Et l'expression arithmétique $((\1+1)?

Actuellement, j'obtiens une mauvaise erreur de jeton \1+1.

2
deanresin

sed et l'arithmétique ne se mélangent pas. Le bon outil pour des travaux comme celui-ci est awk.

Considérez ce fichier de test:

$ cat test.txt
/nonmatching/line 1
/home/username/Pictures/properties/wallpaper/span/tree.jpg 2
/another/non/matching/line 5

Nous pouvons incrémenter le numéro de la ligne que vous souhaitez avec:

$ line="/home/username/Pictures/properties/wallpaper/span/tree.jpg"
$ awk -v f="$line" '$0~f {$NF++} 1' test.txt
/nonmatching/line 1
/home/username/Pictures/properties/wallpaper/span/tree.jpg 3
/another/non/matching/line 5

Comme vous pouvez le voir, cela a incrémenté le nombre sur la ligne qui correspondait à $line.

Une limitation est que ce code, tel qu'il est écrit, ne conservera pas plusieurs blancs sur les lignes pour lesquelles le nombre est incrémenté. Si l'espace est important, nous aurions besoin de plus de définition du format d'entrée.

Comment ça fonctionne

  • -v f="$line"

    Ceci affecte la valeur de la variable Shell line à la variable awk f.

  • $0~f {$NF++}

    Ici, $0~f est une condition. C'est vrai si la ligne d'entrée, notée $0, correspond à l'expression régulière f telle que définie ci-dessus. S'il correspond, l'instruction $NF++ est exécuté. Cela incrémente le dernier champ de la ligne qui, pour votre saisie, est le nombre.

  • 1

    C'est le raccourci cryptique d'awk pour imprimer la ligne.

Modification d'un fichier sur place avec awk

Si vous avez un awk moderne GNU, vous pouvez éditer le fichier en place avec:

gawk -i inplace -v f="$line" '$0~f {$NF++} 1' test.txt

Avec d'autres awks, utilisez:

awk -v f="$line" '$0~f {$NF++} 1' test.txt > tmp.txt && mv -f tmp.txt test.txt

Création text.txt s'il n'existe pas

Dans le cas où le fichier test.txt is ne contient pas de ligne correspondant à $line, cette version aura une telle ligne avec 1 comme décompte:

gawk -i inplace -v f="$line" '$0~f {n=1; $NF++} 1; END{if(!n) print f,1>>FILENAME}' test.txt

Ce code ajoute une variable n. Si $line est dans le fichier, n est défini sur 1. Si ce n'est pas le cas, n reste à la valeur par défaut de 0. Au niveau de END du fichier d'entrée, la valeur de n est testée. Si n est toujours nul, la ligne est ajoutée.

3
John1024