2010-11-13 11 views
2

Je suis en train de faire correspondre plusieurs lignes remplacer un bloc avec sed et je ne peux pas le comprendre ..sélection des lignes avec sed

DATABASES = { 
    'default': { 
     'ENGINE': 'django.db.backends.', # Add 'postgresql_psycopg2', 'postgresql',  'mysql', 'sqlite3' or 'oracle'. 
     'NAME': 'testblah',      # Or path to database file if using  sqlite3. 
     'USER': '',      # Not used with sqlite3. 
     'PASSWORD': '',     # Not used with sqlite3. 
     'HOST': '',      # Set to empty string for localhost. Not used  with sqlite3. 
     'PORT': '',      # Set to empty string for default. Not used  with sqlite3. 
    } 
} 

Je pense que la meilleure façon de le faire serait quelque chose comme ça ;

sed -i "s/^DATABASES\s?+=\s?+{$+8/test/" settings.py 

En bref, je veux trouver le DATABASES = { comprennent les 8 lignes suivantes dans la capture et le remplacer par autre chose.

Des idées de ce qui ne va pas?

+0

Je pense que le problème est que vous n'apportez pas toutes les lignes dans le match, mais cela fait longtemps. Par défaut, le modèle sed n'est exécuté que sur une seule ligne à la fois, vous devez faire quelques trucs pour amener la ligne suivante en utilisant d'autres commandes. – caveman

Répondre

1

Les expressions régulières ne sont pas assez puissantes pour correspondre exactement à des paires d'accolades. Vous auriez besoin d'une grammaire sans contexte pour cela. Voici le plus proche de ce que vous êtes question initiale demandait que sed peut faire:

Remplacer la ligne commençant par DATABASES et 9 lignes suivantes avec test

sed -n -e '/^DATABASES/i test' -e '/^DATABASES/{n;n;n;n;n;n;n;n;n;n;};p' settings.py 
+0

C'est exactement ce que je voulais faire, merci! –

2
$ cat > f.sed 
/^DATABASES/,/^}/c\ 
\ 
A block of replacement\ 
...text. 
$ sed -f f.sed test.txt 

Mise à jour: En général, on devrait regarder à SO répond comme directions à prendre plutôt que des recettes finies. Comme Brian le fait remarquer, les détails dans les expressions régulières affecteront la façon dont la réponse est générale et précise. Vous voudrez peut-être faire une suggestion donnée plus de l'un ou l'autre w.r.t. n'importe quelle classe de motif ...

+0

Le problème avec ceci est qu'il suppose qu'il n'y aura pas d'autre '}' dans le fichier après la fin de la chaîne DATABASE JSON. Par exemple, dupliquez l'entrée deux fois et changez la seconde BASE DE DONNEES en FOO. Il va remplacer les deux. –

+0

J'ai raté le '^' avant le '}'. Cela ne fonctionne que si la dernière accolade (et seulement la dernière accolade) est au début de la ligne. C'est bien si le texte est bien formé. Je vais supprimer mon vote négatif. EDIT: bizarre, il ne semble pas vouloir me laisser annuler mon vote. –

+0

@Brian, eh, ne t'inquiète pas, j'ai beaucoup de points. Stackoverflow est chanceux d'avoir des gens comme vous analysant soigneusement la base de données en pleine croissance. (Je vais éditer la question, cependant, qui va résoudre le timelock de rétraction.) – DigitalRoss

1

Si vous n'êtes pas obligé d'utiliser sed, grep -A 8 'votre expression rationnelle' pourrait fonctionner. (GNU grep)

1

Ceci est probablement plus facile à résoudre en perl qu'en sed. D'une part, il est trivial de faire des matchs multilignes.

perl -0777 -pe 's/foo.*?bar/glarch/sg' 

Mais pour une autre, vous pouvez effectivement faire de la correspondance récursive avec des crochets imbriqués, que je crains que vous devrez peut-être ici. De plus, puisque Perl utilise EREs et sed utilise BREs, vous aurez plus de facilité car vous n'aurez pas besoin d'autant de backslashes.

De plus, tous les éléments de type \s+ sont pris en charge.

De plus, s'il s'agit d'un texte UTF-8, tout ira toujours bien; ajoutez simplement un drapeau de ligne de commande de type -CSD.

De plus, il existe un traducteur sed-to-perl appelé s2p, donc vous savez que c'est un sur-ensemble correct.

Gosh, c'est sûr beaucoup de aussi s. ☺

Questions connexes