Reputation: 183
I want to replace specific strings in a text stream with the output of a program run on those strings. For example, replace any occurrence of "#filename#" with the output of identify filename
Is there any easy way to do this?
Upvotes: 1
Views: 1722
Reputation: 753970
Assuming 'identify filename
' is itself a command, then I think you'll need to use Perl for this. In the best Perl inscrutable style:
while (<>)
{
s/#(\w+)#/my $x = qx%identify $1%; chomp $x; $x/e;
print;
}
This reads a line of input ('<>
') into the implicit variable '$_
'; the next line applies a substitute operation to the implicit variable - more details in a moment - and then the 'print
' prints the implicit variable.
As to the substitute operation 's///
', the first part looks for a hash '#', a series of one or more 'word' characters - alphanumerics or underscore - and another hash, making the identified file name available as '$1
'. The second part is the replacement string. After the third slash is the modifier 'e
' which means 'execute the replacement as bit of Perl'. And the relevant bit of Perl is:
my $x = qx%identify $1%; chomp $x; $x
The first part executes the command 'identify filename
' if the string between the hash marks is 'filename', saving the output, newline and all, in local variable $x. The 'chomp
' operation removes the newline; the final '$x
' yields a value - the string that was output by the 'identify' command. (Somewhat to my surprise, Perl does not allow a simpler looking: s/#(\w+)#/chomp qx%identify $1%/e
; the error was 'Can't modify quoted execution (``, qx) in chomp at xx.pl line 3, near "qx%identify $1%)"
'.)
Consider the 'identify' command:
echo "identified file $1 as $PWD/$1"
Now consider the input line:
abc#def#ghi
The output is:
abcidentified file def as /Users/jleffler/tmp/soq/defghi
(where /Users/jleffler/tmp/soq
happened to be my current directory while running the command).
Rather less inscrutably:
while (my $line = <>)
{
if ($line =~ m/#(\w+)#/)
{
my $identity = qx{identify $1};
chomp $identity;
$line =~ s/#\w+#/$identity/;
}
print $line;
}
Certainly not as compact, but the explanation is very similar.
Note that the initial edition is not the most compact form possible. Consider this version:
perl -p -e 's/#(\w+)#/my $x = qx%identify $1%; chomp $x; $x/e'
The '-p' option places the script (the argument to '-e') in a read, execute, print loop (REPL).
That's one of the wonders of Perl - TMTOWTDI (pronounced 'tim-toady') - There's More Than One Way To Do It.
Upvotes: 3
Reputation: 2831
REPLACEMENT=`identify filename`
sed "s/#filename#/$REPLACEMENT/g"
EDIT: See Dennis Williamson's comment.
Upvotes: 0