2008-10-27 4 views
3

Je dois parcourir les fichiers dans un répertoire et effectuer le remplacement suivant.Comment modifier le format des variables de substitution dans un modèle

Avant:

Hello ${USER_NAME}, you live at ${HOME_ADDRESS}. It is now ${TIME}

Après:

Hello ${userName}, you live at ${homeAddress}. It is now ${time}

Le nombre de jetons différents qui apparaissent dans $ {} est grande, il est donc pas vraiment possible de courir:

find . -name '*' -exec sed -i 's/${USER_NAME}/${userName}/g' {} \; 
find . -name '*' -exec sed -i 's/${TIME}/${time}/g' {} \; 

etc.

J'espère qu'il est possible d'effectuer ce remplacement à l'aide d'une seule commande, qui ressemble à:

find . -name '*' -exec sed 's/XXX/YYY/g' {} \; 

Mais je ne peux pas comprendre ce qui se substituer à XXX et YYY. Est-il possible de le faire en une seule commande?

Cheers, Donal

+0

Si le temps d'exécution est une grosse contrainte, pensez à utiliser gawk, perl ou python lors de la compilation d'octets au début pour accélérer l'exécution. Je ne suis pas du tout certain que sed fasse cela. – dmckee

+0

Merci, mais le temps d'exécution est sans importance –

Répondre

2

Le drapeau -i à sed va éditer un fichier en place. Pour XXX et YYY, vous devez utiliser quelque chose comme:

sed -i 's/USER_NAME/userName/g' 

et ainsi de suite.

Mise à jour: Je vois que votre question était vraiment de changer automatiquement "USER_NAME" en "userName". Vous pouvez essayer ce script Perl:

sub convert { 
    my $r = lc $_[0]; 
    $r =~ s/_(.)/\U$1\E/g; 
    return $r; 
} 
while (<>) { 
    s/\${([A-Z_]+)}/\${@{[convert $1]}}/g; 
    print; 
} 

Exécuter comme ceci:

perl -i convert.pl inputfile.txt 

Exemple de sortie:

$ cat inputfile.txt 
Hello ${USER_NAME}, you live at ${HOME_ADDRESS}. It is now ${TIME} 
$ perl -i convert.pl inputfile.txt 
$ cat inputfile.txt 
Hello ${userName}, you live at ${homeAddress}. It is now ${time} 
+0

Je reçois l'erreur suivante: "Impossible de faire inplace edit sans sauvegarde à la ligne 6 de convert.pl" Cependant, si je supprime le "-i" drapeau, il semble fonctionner, donc je suppose que je vais juste rediriger la sortie, puis renommer les fichiers. Merci! –

+0

On dirait que vous êtes sur Windows: -i ne fonctionnera pas sans une extension de sauvegarde. Utilisez -i.bak, cela renommera foo en foo.bak avant d'écraser foo. – ephemient

+0

Merci, j'ai également découvert que le script ci-dessus incorrectement renommé $ {FOO_IMG_SRC} à $ {fooImg_src} –

4

Formaté pour plus de clarté:

sed -i '/^Hello/ { s/\$\{USER_NAME\}/\$\{userName\}/g 
        s/\$\{HOME_ADDRESS\}/\$\{homeAddress\}/g 
        s/\$\{TIME\}/\$\{time\}/g 
        }' 

/^Hello/ identifie le l ines vous souhaitez agir (le rendre plus spécifique si nécessaire) et le reste remplace chaque nom de variable.


Si vous écrivez ceci dans un script envisager l'utilisation d'un document ICI pour conserver la mise en forme et de le rendre plus facile à lire et mettre à jour ...

+0

Si je veux appliquer le remplacement à toutes les lignes, je suppose que je viens d'omettre '/^Bonjour /'? –

+0

Yup. Et vous pouvez utiliser deux adresses là-bas "/^Bonjour// Goodbye $/{...}" pour travailler et toutes les lignes entre Bonjour et au revoir (inclus). – dmckee

0

La réponse ci-dessus fonctionne vraiment bien. Pour être complet, je pourrais ajouter que vous pouvez faire:

sed '/^Hello/ { s/\$\{USER_NAME\}/\$\{userName\}/g' <filename> \ 
    | sed 's/\$\{HOME_ADDRESS\}/\$\{homeAddress\}/g' \ 
    | sed 's/\$\{TIME\}/\$\{time\}/g' 

Ils sont fonctionnellement identiques (sauf que la mine dépotoirs à stdout, vous devrez le mettre quelque part (mais vous obtenez de garder l'original en cas, comme e, tu gâches régulièrement sur tes expressions rationnelles).J'aime ma formulation juste parce que je peux commencer avec la commande sed, puis ajouter plus avec

!! | sed 'yet-enother-regexp' 

Touches fléchées? vi-mode? Qui a besoin de ça? :)

Questions connexes