Shell脚本:将匹配的文本替换为程序的输出

时间:2010-11-27 01:25:32

标签: perl shell command-line

我想用这些字符串上运行的程序的输出替换文本流中的特定字符串。例如,将任何出现的“#filename#”替换为identify filename

的输出

有没有简单的方法可以做到这一点?

2 个答案:

答案 0 :(得分:3)

假设'identify filename'本身就是一个命令,那么我认为你需要使用Perl。在最好的Perl难以理解的风格:

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

这会将一行输入('<>')读入隐式变量“$_”;下一行对隐式变量应用替换操作 - 稍后更多细节 - 然后'print'打印隐式变量。

对于替换操作's///',第一部分查找散列'#',一系列一个或多个'word'字符 - 字母数字或下划线 - 以及另一个散列,生成标识的文件名称可用作“$1”。第二部分是替换字符串。在第三个斜杠之后是修饰符'e',这意味着'执行替换为Perl的位'。而Perl的相关部分是:

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

如果散列标记之间的字符串是'filename',则第一部分执行命令'identify filename',将输出,换行符和全部保存在局部变量$ x中。 “chomp”操作会删除换行符;最后的'$x'产生一个值 - 'identify'命令输出的字符串。 (有点令我惊讶的是,Perl不允许更简单的查看:s/#(\w+)#/chomp qx%identify $1%/e;错误是“Can't modify quoted execution (``, qx) in chomp at xx.pl line 3, near "qx%identify $1%)"”。)

考虑'识别'命令:

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

现在考虑输入行:

abc#def#ghi

输出结果为:

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

(运行命令时/Users/jleffler/tmp/soq恰好是我当前的目录。)

相当不那么难以理解:

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

当然不那么紧凑,但解释非常相似。

请注意,初始版本不是最紧凑的形式。考虑这个版本:

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

'-p'选项将脚本(参数'-e')置于读,执行,打印循环(REPL)中。

这是Perl的奇迹之一 - TMTOWTDI(发音为'tim-toady') - 有多种方法可以做到。

答案 1 :(得分:0)

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

编辑:见丹尼斯威廉姆森的评论。