2010-11-27 30 views
1

Je souhaite remplacer des chaînes spécifiques dans un flux de texte par la sortie d'un programme exécuté sur ces chaînes. Par exemple, remplacez toute occurrence de "# nom_fichier #" avec la sortie de identify filenameScript shell: remplace le texte correspondant par la sortie du programme

Existe-t-il un moyen simple de faire cela?

+0

Avez-vous besoin de changer la chaîne de remplacement dynamiquement ou la sortie de 'identify identifier' static (pour ce flux)? –

+0

Je veux changer la sortie de manière dynamique: je ne peux pas prédire quels noms de fichiers j'aurai jusqu'à ce que je les voie. – nikitakit

Répondre

3

En supposant que 'identify filename' est lui-même une commande, alors je pense que vous aurez besoin d'utiliser Perl pour cela. Dans le meilleur style Perl insondable:

while (<>) 
{ 
    s/#(\w+)#/my $x = qx%identify $1%; chomp $x; $x/e; 
    print; 
} 

Ce lit une ligne d'entrée ('<> ') dans la variable implicite' $_'; la ligne suivante applique une opération de remplacement à la variable implicite - plus de détails dans un instant - puis le 'print' imprime la variable implicite. En ce qui concerne l'opération de remplacement 's///', la première partie recherche un hash '#', une série d'un ou plusieurs caractères 'word' - caractères alphanumériques ou traits de soulignement - et un autre hash, rendant le nom de fichier identifié disponible '$1'. La deuxième partie est la chaîne de remplacement. Après la troisième barre oblique est le modificateur 'e' qui signifie 'exécuter le remplacement en tant que bit de Perl'. Et le bit correspondant de Perl est:

my $x = qx%identify $1%; chomp $x; $x 

La première partie exécute la commande « identify filename » si la chaîne entre les marques de hachage est « filename », sauver la sortie, les nouvelles lignes et tous, dans la variable locale $ x. L'opération 'chomp' supprime la nouvelle ligne; le '$x' final donne une valeur - la chaîne qui a été sortie par la commande 'identify'. (Un peu à ma grande surprise, Perl ne permet pas une simple recherche: s/#(\w+)#/chomp qx%identify $1%/e, l'erreur était 'Can't modify quoted execution (``, qx) in chomp at xx.pl line 3, near "qx%identify $1%)"'.)

Tenir compte de la commande 'identifier':

echo "identified file $1 as $PWD/$1" 

Considérons maintenant la ligne d'entrée:

abc#def#ghi 

La sortie est la suivante:

abcidentified file def as /Users/jleffler/tmp/soq/defghi 

(où /Users/jleffler/tmp/soq est arrivé à être mon répertoire actuel lors de l'exécution de la commande).

Plutôt moins impénétrable:

while (my $line = <>) 
{ 
    if ($line =~ m/#(\w+)#/) 
    { 
     my $identity = qx{identify $1}; 
     chomp $identity; 
     $line =~ s/#\w+#/$identity/; 
    } 
    print $line; 
} 

Certainement pas aussi compact, mais l'explication est très similaire.

Notez que l'édition initiale n'est pas la forme la plus compacte possible. Considérez cette version:

perl -p -e 's/#(\w+)#/my $x = qx%identify $1%; chomp $x; $x/e' 

L'option -p place le script (l'argument -e) dans une lecture, exécution, boucle d'impression (REMP).

C'est l'une des merveilles de Perl - TMTOWTDI (prononcé 'tim-toady') - Il y a plus d'une façon de le faire.

+0

Exactement ce que je cherchais. Merci beaucoup. Permettez-moi d'ajouter, cependant, que (\ w +) n'est pas la meilleure correspondance pour les noms de fichiers: il n'accepte pas les points. – nikitakit

+0

@nikitakit: sans doute correct - mais c'est là que vous savez quelles règles vous devez appliquer et je ne peux pas le dire. Vous pouvez envisager d'utiliser une regex telle que '\ w [\ w /.] * \ W'' pour récupérer les noms de fichiers qui commencent et se terminent par un alphanumérique mais qui peuvent contenir des barres obliques et des points. Ou vous pouvez affiner/étendre la règle de nombreuses façons. Une regex très acceptée est '[^ #] + ''; il accepte tout sauf les hachages entre les deux marques de hachage. –

0
REPLACEMENT=`identify filename` 
sed "s/#filename#/$REPLACEMENT/g" 

EDIT: Voir le commentaire de Dennis Williamson.

+2

Vous devez remplacer les guillemets simples par des guillemets doubles pour que cela fonctionne. Le '# 'n'a pas besoin d'être échappé. –