Je voudrais modifier un fichier sur place en ajoutant une ligne, seulement s'il n'existe pas encore pour rendre mon script à l'épreuve des balles.
Normalement, je ferais quelque chose comme:
cat >> ~/.bashrc <<EOF
export PATH=~/.composer/vendor/bin:\$PATH
EOF
Il est également possible de le faire via ansible ( line
+ insertafter=EOF
+ regexp
), mais c'est une autre histoire.
Dans vi / ex, je pourrais faire quelque chose comme:
ex +'$s@$@\rexport PATH=\~/.composer/vendor/bin:$PATH@' -cwq ~/.bashrc
mais comment puis-je vérifier si la ligne est déjà là (et donc ne rien faire) idéalement sans répéter la même ligne?
Ou peut-être existe-t-il un moyen plus simple de le faire dans l'éditeur Ex?
substitute
ex-command
Kenorb
la source
la source
grep -Fq 'export PATH=~/.composer/vendor/bin:$PATH' ~/.bashrc || ex ...
(oucat
, d'ailleurs)?ex ~/.bashrc -c "if search('export PATH=\~\/.composer\/vendor\/bin:\$PATH')>0 | norm quit | endif | norm Aexport PATH=~/.composer/vendor/bin:$PATH"
export
c'est une commande , donc le reste de la ligne est un mot shell, PAS une affectation. Par conséquent, contrairement à une affectation de variable (qui n'utilise pasexport
), vous avez besoin de guillemets doubles ou elle se cassera sur les espaces . Voir également Comment ajouter correctement un chemin d'accès à PATH .Réponses:
Si vous voulez une protection contre les balles , vous voulez probablement quelque chose d'un peu plus portable que les options compliquées ci-dessus. Je m'en tiendrai aux fonctionnalités POSIX de
ex
et le rendrais stupide-simple: supprimez simplement la ligne si elle est là (quel que soit le nombre de fois où elle est là), ajoutez-la à la fin du fichier, puis enregistrez et quittez:J'ai ancré l'expression régulière pour plus de robustesse, bien que je pense qu'il est presque impossible de faire correspondre accidentellement cette expression régulière. (Ancré signifie utiliser
^
et$
donc l'expression régulière ne correspondra que si elle correspond à une ligne entière .)Notez que la
+cmd
syntaxe n'est pas requise par POSIX, ni la caractéristique commune d'autoriser plusieurs-c
arguments.Il existe une multitude d'autres façons simples de procéder. Par exemple, ajoutez la ligne à la fin du fichier, puis exécutez les deux dernières lignes du fichier via le filtre UNIX externe
uniq
:Ceci est très très propre et simple, et est également entièrement compatible POSIX. Il utilise la fonction d'échappement de
ex
pour le filtrage de texte externe et l' utilitaire shell spécifié par POSIXuniq
L' essentiel est,
ex
est conçu pour l'édition de fichiers sur place et c'est de loin le moyen le plus portable pour y parvenir de manière non interactive. Il est même antérieur à l'originalvi
, en fait - le nomvi
est pour "éditeur visuel", et l'éditeur non visuel sur lequel il a été construit étaitex
.)Pour encore plus de simplicité (et pour le réduire à une seule ligne), utilisez
printf
pour envoyer les commandes àex
:la source
Une solution possible consiste à créer une fonction pour ce faire:
Nous créons d'abord une variable locale
l:res
qui sera utilisée pour compter le nombre d'occurrences de la ligne.Nous utilisons la
global
commande: chaque fois que la ligne est appariée, ellel:res
est incrémentée.Enfin si
l:res
est toujours 0 cela signifie que la ligne n'apparaît pas dans le fichier donc on passe à la dernière ligne grâce àG
, et on crée une nouvelle ligne aveco
laquelle on écrit la ligne à ajouter.Remarque 1 La méthode que j'ai utilisée pour définir la valeur de
l:res
est un peu lourde et pourrait être remplacée par celle suggérée par @Alex dans sa réponse par quelque chose comme:Remarque 2 Pour rendre la fonction plus flexible, vous pouvez également utiliser des arguments:
escape()
pour ajouter un\
devant les caractères qui pourrait causer un problème dans la recherche.Notez également que vous devrez toujours échapper
\
par vous-même lors de l'appel de la fonction (je n'ai pas réussi à m'échapper\
automatiquement):la source
Essayer:
Notez que
:append
cela ne fonctionnera pas à l'intérieur deif endif
-block avec le mode Ex (voir VimDoc ) donc je dois le mettre à l'norm A...
extérieur.la source
J'utilise normalement:
la source
Afin de simplifier et d'éviter la présence de plusieurs
\
, la ligne à ajouter seraexport PATH=mybin:PATH
.Stratégie principale: remplacer le "non
mybin
" texte (tous les fichiers) par text + mybin-path-definition:ou avec une indentation plus didactique :
Si nous avons un match:
&
a le texte intégral debashrc
et&
ne contient pas/mybin:/
alors:
MISE À JOUR : Enfin, nous pouvons faire un script vim:
chmod 755 et installez-le. Usage:
bashrcfix
attention: en
\v
mode,=
signifie facultatifla source
La plupart de ces réponses semblent compliquées, que diriez-vous de bonnes vieilles commandes shell:
Cela pourrait facilement être une fonction Bash:
EDIT : Le code de sortie de grep est important et dans ce cas, il doit être inversé
! grep
.grep -v
ne sortira pas comme prévu dans cette situation. Merci @joeytwiddle pour l'astuce.la source
grep -v
vous donne le code de sortie que vous souhaitez. Mais! grep
devrait le faire.-v
juste!
.-F
pour negrep
pas interpréter les caractères comme des expressions régulières, et 2. Utiliser-q
au lieu de rediriger vers/dev/null
. Voir mon commentaire précédent sur la question .-q
et-F
options? Je pensais que>/dev/null
c'était plus universel entre différentes plates-formes (sun vs hp vs Mac OS X vs Ubuntu vs FreeBSD vs…)