2010-12-14 24 views
6

Comment faire fonctionner sed sur des parties spécifiques d'une ligne uniquement? Et, au contraire, comment je fais que sed ne fonctionne pas sur des parties spécifiques d'une ligne?Comment opérer sur une partie de la ligne seulement

Exemples:

"A a A a (A a) A (a A) a" 

Comment, par exemple, remplacer tous les A s avec T s que entre le ( et ) obtenir:

"A a A a (T a) A (a T) a" 

Et donné exemple suivant entrée:

"F f F f (F f) F (f F) f" 

Comment, par exemple, remplacer tous les F s avec X s mais pas entre à obtenir ( et ):

« X f X f (F f) X (f F) f "

J'ai cherché Google, mais je n'ai trouvé rien d'utilisable. Je suppose que c'est une question générale à propos de sed. Le problème est réductible à des "modèles" généraux, je l'espère.

  1. ayant et TO alors fonctionner entre eux seulement (sur toutes les occurrences sur la ligne donnée)
  2. ayant et opérer ailleurs que entre eux ...
  3. cas particulier lorsque FROM et TO sont les même (entre « et » ou « FOO » et « FOO », etc.) pour les 1. et 2.

Il devrait fonctionner avec toute opération, non seulement une substitution, mais aussi avec l'impression, etc., comme impression tout entre les chaînes "FOO" et "BAR" dans la chaîne.

"1 2 3 BAR a b c FOO d e f BAR g a h FOO i j k BAR l m n FOO o p q" 

Le résultat sera

" d e f i j k " 

Ainsi, des exemples généraux sur la façon de le faire serait très appréciée. Il semble aussi que cette question soit assez courante, mais aucun bon howto ne se trouve encore sur Google. Je suppose également que ce serait assez difficile à répondre. S'il vous plaît, ne donnez pas non plus de conseils sur la façon de le faire en utilisant Perl, AWK ou tout autre que sed. Cette question est vraiment une question sed-only.

+0

J'ai fait de mon mieux. Mon idée était de diviser la ligne en morceaux par le FROM et TO (en quelque sorte) et ensuite "en quelque sorte" (je ne sais pas encore comment) d'opérer soit sur des parties paires ou impaires seulement ou quelque chose de semblable. Si je savais comment le faire, je ne serais pas demandé ici. Et, il est très probable que mon idée de scission puisse être fausse. C'est assez difficile et j'avais l'habitude d'utiliser sed pour des tâches simples seulement auparavant. – mjf

Répondre

1

Diviser et conquérir. Utilisez les lignes de début, (^), la fin de la ligne ($) et les caractères de délimitation (entre parenthèses dans ce cas) comme ancres et boucle. Les nouvelles lignes ajoutées sont supprimées à la fin.

$ echo "A a A a (A a) A (a A) a" | 
    sed 's/([^)]*)/\n&/g; 
     :a; 
      s/\(\n([^)]*\)A\([^)]*)\)/\1T\2/; 
     ta; 
     s/\n//g' 
A a A a (T a) A (a T) a 
$ echo "F f F f (F f) F (f F) f" | 
    sed 's/(/\n(/g; 
     s/)/)\n/g; 
     :a; 
      s/\([^(]*\)F\([^)]*\(\n\|$\)\)/\1X\2/g; 
     ta; 
     s/\n//g' 
X f X f (F f) X (f F) f 
$ echo "1 2 3 BAR a b c FOO d e f BAR g a h FOO i j k BAR l m n FOO o p q" | 
    sed 's/^/BAR/; 
     s/$/FOO/; 
     s/FOO/&\n/g; 
     s/BAR/\n&/g; 
     s/BAR[^\n]*\n//g; 
     s/[^\n]*FOO\n//g; 
     s/\n//g' 
d e f i j k 
+0

Merci. Donnez-moi le temps de le parcourir, s'il vous plaît. – mjf

+0

Que se passe-t-il si je veux remplacer, par exemple, toutes les sections AROUND entourées de caractères "[" et "]" comme dans une expression régulière? La tâche est similaire à la transformation de regex normale (où tous les caractères "() [] {} | +?" N'ont pas besoin d'être échappés), par exemple, expression grep ou sed, où les caractères spéciaux doivent être échappés. Je veux dire, étant donné, disons, l'expression sed suivante sans échapper aux caractères qui doivent être échappés dans la syntaxe sed pour en faire des caractères spéciaux que je voudrais appliquer sur le programme sed de l'espace AROUND suivant: "s/\\ ([] [() {} | +?] \\)/\\\ 1/g ". L'entrée serait la même "s/([] [() {} | +?])/\\\ 1/g". – mjf

+0

Je maintiens la base de données des regex POSIX BASIC sous la forme où "^. [$() | * +? {\" Caractères doivent être échappés avec "\" pour les rendre "non-spécial" (man 7 regex). J'ai besoin d'un script pour transformer ces expressions régulières en une forme dont j'ai besoin à un moment donné, disons la forme grep (1). Ensuite, j'en ai besoin, disons, de la forme sed (1), ou de la forme de l'éditeur vi, etc. La transformation manuelle des regexes est douloureuse et maintenant le db a pris une taille énorme. Transformer manuellement toutes les regexes, même dans un éditeur aussi intelligent que vi est, est douloureux. J'ai besoin d'un script pour cette tâche, ce qui était ma motivation initiale pour poser cette question. – mjf

1

Cela pourrait fonctionner pour vous (GNU sed):

sed ':a;s/\(([^)]*\)A/\1T/;ta' file # for case 1 

sed ':a;s/\(([^)]*\)F/\1\n/;ta;y/F\n/TF/' file # for case 2 

Pour le cas 1 utiliser une boucle pour remplacer A 's crochets à l'intérieur de T' s.

Pour le cas 2 utilisent le même que ci-dessus pour changer F « s entre parenthèses à l'intérieur des sauts de ligne, puis de traduire F » s et les nouvelles lignes de X « s et s » F respectivement.

Cas n ° 3 est un peu plus complexe, mais peut se faire en 2 commandes de remplacement:

sed -r 's/FOO|BAR/\n&/g;s/[^\n]*(\nBAR[^\n]*)*(\nFOO([^\n]*)\nBAR)?(\nFOO[^\n]*$)?/\3/g' file 

préfixe d'abord chaque FOO et BAR chaînes avec des sauts de ligne. Recherchez ensuite toutes les combinaisons de FOO et BAR et conservez uniquement les chaînes entre FOO et BAR. Les nouvelles lignes permettent l'utilisation de la classe négative pour simplifier la procédure.